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

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

commit 8ae335d87fa650f5aa3ffd99da5d4a693fcc5eba
Author: angela <[email protected]>
AuthorDate: Thu Mar 18 18:30:57 2021 +0100

    SLING-10219 : Expand enforcing principal-based authorization option to 
repo-init (initial draft)
---
 pom.xml                                            |  12 +-
 .../cpconverter/accesscontrol/AclManager.java      |   3 +
 .../accesscontrol/DefaultAclManager.java           | 109 +++++++++--
 .../cpconverter/accesscontrol/EnforceInfo.java     |  29 +++
 .../AbstractConfigurationEntryHandler.java         |   8 +-
 .../handlers/NodeTypesEntryHandler.java            |  17 +-
 .../cpconverter/repoinit/AccessControlVisitor.java | 198 ++++++++++++++++++++
 .../cpconverter/repoinit/ConversionMap.java        |  81 +++++++++
 .../cpconverter/repoinit/DefaultVisitor.java       | 198 ++++++++++++++++++++
 .../feature/cpconverter/repoinit/NoOpVisitor.java  | 118 ++++++++++++
 .../cpconverter/repoinit/OperationProcessor.java   |  53 ++++++
 .../cpconverter/repoinit/SystemUserVisitor.java    |  52 ++++++
 .../feature/cpconverter/shared/NodeTypeUtil.java   |  47 +++++
 .../handlers/ConfigurationEntryHandlerTest.java    |   3 +-
 .../feature/cpconverter/handlers/RepoInitTest.java | 201 +++++++++++++++++++++
 ....RepositoryInitializer-conversion-result.config |  45 +++++
 ...it.RepositoryInitializer-conversion-test.config |  39 ++++
 ....RepositoryInitializer-no-conv-with-diff.config |  34 ++++
 ...RepositoryInitializer-no-conversion-test.config |  72 ++++++++
 19 files changed, 1279 insertions(+), 40 deletions(-)

diff --git a/pom.xml b/pom.xml
index c97c1d0..d82a3d7 100644
--- a/pom.xml
+++ b/pom.xml
@@ -122,6 +122,12 @@
       <scope>provided</scope>
     </dependency>
     <dependency>
+      <groupId>org.apache.sling</groupId>
+      <artifactId>org.apache.sling.repoinit.parser</artifactId>
+      <version>1.6.6</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
       <groupId>org.apache.felix</groupId>
       <artifactId>org.apache.felix.converter</artifactId>
       <version>1.0.14</version>
@@ -241,12 +247,6 @@
       <version>${mockito-core.version}</version>
       <scope>test</scope>
     </dependency>
-    <dependency>
-      <groupId>org.apache.sling</groupId>
-      <artifactId>org.apache.sling.repoinit.parser</artifactId>
-      <version>1.6.4</version>
-      <scope>test</scope>
-    </dependency>
   </dependencies>
 
   <build>
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 95f2f75..4c81b91 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
@@ -22,6 +22,7 @@ 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.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * The Manager able to collect and build System Users and related ACL policies.
@@ -40,6 +41,8 @@ public interface AclManager {
 
     void addRepoinitExtension(@NotNull List<VaultPackageAssembler> 
packageAssemblers, @NotNull FeaturesManager featureManager);
 
+    void addRepoinitExtention(@Nullable String repoInitText, @Nullable String 
runMode, @NotNull FeaturesManager featuresManager);
+
     void addNodetypeRegistrationSentence(@NotNull String 
nodetypeRegistrationSentence);
 
     void addPrivilegeDefinitions(@NotNull PrivilegeDefinitions 
privilegeDefinitions);
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 ce4b708..a399bb0 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
@@ -21,10 +21,16 @@ import org.apache.jackrabbit.spi.PrivilegeDefinition;
 import org.apache.jackrabbit.spi.commons.conversion.DefaultNamePathResolver;
 import org.apache.jackrabbit.spi.commons.conversion.NameResolver;
 import org.apache.jackrabbit.vault.fs.spi.PrivilegeDefinitions;
+import org.apache.jackrabbit.vault.util.PathUtil;
 import org.apache.jackrabbit.vault.util.PlatformNameFormat;
+import org.apache.jackrabbit.vault.util.Text;
 import org.apache.sling.feature.cpconverter.features.FeaturesManager;
+import org.apache.sling.feature.cpconverter.repoinit.OperationProcessor;
 import org.apache.sling.feature.cpconverter.shared.RepoPath;
 import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
+import org.apache.sling.repoinit.parser.RepoInitParsingException;
+import org.apache.sling.repoinit.parser.impl.RepoInitParserService;
+import org.apache.sling.repoinit.parser.operations.Operation;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.slf4j.Logger;
@@ -33,11 +39,11 @@ import org.slf4j.LoggerFactory;
 import javax.jcr.NamespaceException;
 import java.io.File;
 import java.io.FileInputStream;
+import java.io.StringReader;
 import java.util.Collection;
-import java.util.HashSet;
-import java.util.Optional;
 import java.util.Formatter;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
@@ -45,18 +51,20 @@ import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.Set;
 import java.util.function.Predicate;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 
-public class DefaultAclManager implements AclManager {
+public class DefaultAclManager implements AclManager, EnforceInfo {
 
     private static final Logger log = 
LoggerFactory.getLogger(DefaultAclManager.class);
 
     private static final String CONTENT_XML_FILE_NAME = ".content.xml";
 
     private final RepoPath enforcePrincipalBasedSupportedPath;
+    private final OperationProcessor processor = new OperationProcessor();
 
     private final Set<SystemUser> systemUsers = new LinkedHashSet<>();
     private final Set<Group> groups = new LinkedHashSet<>();
@@ -149,6 +157,29 @@ public class DefaultAclManager implements AclManager {
         }
     }
 
+    @Override
+    public void addRepoinitExtention(@Nullable String repoInitText, @Nullable 
String runMode, @NotNull FeaturesManager featuresManager) {
+        if (repoInitText == null || repoInitText.trim().isEmpty()) {
+            return;
+        }
+
+        try (Formatter formatter = new Formatter()) {
+            if (enforcePrincipalBased()) {
+                List<Operation> ops = new RepoInitParserService().parse(new 
StringReader(repoInitText));
+                processor.apply(ops, formatter,this);
+            } else {
+                formatter.format("%s", repoInitText);
+            }
+
+            String text = formatter.toString().trim();
+            if (!text.isEmpty()) {
+                featuresManager.addOrAppendRepoInitExtension(text, runMode);
+            }
+        } catch (RepoInitParsingException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
     private void addUsersAndGroups(@NotNull Formatter formatter) {
         for (SystemUser systemUser : systemUsers) {
             // make sure all system users are created first
@@ -172,16 +203,8 @@ public class DefaultAclManager implements AclManager {
     @NotNull
     private String calculateIntermediatePath(@NotNull SystemUser systemUser) {
         RepoPath intermediatePath = systemUser.getIntermediatePath();
-        if (enforcePrincipalBased(systemUser) && 
!intermediatePath.startsWith(enforcePrincipalBasedSupportedPath)) {
-            RepoPath parent = intermediatePath.getParent();
-            while (parent != null) {
-                if (enforcePrincipalBasedSupportedPath.startsWith(parent)) {
-                    String relpath = 
intermediatePath.toString().substring(parent.toString().length());
-                    return enforcePrincipalBasedSupportedPath.toString() + 
relpath;
-                }
-                parent = parent.getParent();
-            }
-            throw new IllegalStateException("Cannot calculate intermediate 
path for service user. Configured Supported path " 
+enforcePrincipalBasedSupportedPath+" has no common ancestor with 
"+intermediatePath);
+        if (enforcePrincipalBased(systemUser)) {
+            return 
calculateEnforcedIntermediatePath(intermediatePath.toString());
         } else {
             return intermediatePath.toString();
         }
@@ -248,17 +271,20 @@ public class DefaultAclManager implements AclManager {
         }
     }
 
+    private boolean enforcePrincipalBased() {
+        return enforcePrincipalBasedSupportedPath != null;
+    }
+
     private boolean enforcePrincipalBased(@NotNull SystemUser systemUser) {
-        if (enforcePrincipalBasedSupportedPath == null) {
-            return false;
-        } else {
+        if (enforcePrincipalBased()) {
             if (mappedById.contains(systemUser.getId())) {
-                log.warn("Skip enforcing principalbased access control setup 
for system user {} due to existing mapping", systemUser.getId());
+                log.warn("Skip enforcing principal-based access control setup 
for system user '{}' due to existing mapping by id.", systemUser.getId());
                 return false;
             } else {
                 return true;
             }
         }
+        return false;
     }
 
     private void writeEntry(@NotNull AccessControlEntry entry, @NotNull String 
path, @NotNull Formatter formatter) {
@@ -296,6 +322,55 @@ public class DefaultAclManager implements AclManager {
         privilegeDefinitions = null;
     }
 
+    @Override
+    public boolean enforcePrincipalBased(@NotNull String serviceUserId) {
+        // FIXME get rid of duplication with enforePrincipalBased(SystemUser)
+        // FIXME get rid of streming mappings multiple times
+        if (enforcePrincipalBased()) {
+            if (mappings.stream().anyMatch(mapping -> 
mapping.mapsUser(serviceUserId))) {
+                log.warn("Skip enforcing principal-based access control setup 
for system user '{}' due to existing mapping by id.", serviceUserId);
+                return false;
+            } else {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    @NotNull
+    public String calculateEnforcedIntermediatePath(@Nullable String 
intermediatePath) {
+        if (enforcePrincipalBasedSupportedPath == null) {
+            return intermediatePath;
+        }
+        String supportedPath = enforcePrincipalBasedSupportedPath.toString();
+        if (intermediatePath == null || intermediatePath.isEmpty()) {
+            return enforcePrincipalBasedSupportedPath.toString();
+        } else if (Text.isDescendantOrEqual(supportedPath, intermediatePath)) {
+            return intermediatePath;
+        } else if (!intermediatePath.startsWith("/")) {
+            String p = "/"+intermediatePath;
+            while (!p.isEmpty()) {
+                if (supportedPath.contains(p)) {
+                    String relpath = intermediatePath.substring(p.length());
+                    return supportedPath + "/" +relpath;
+                }
+                p = Text.getRelativeParent(p, 1);
+            }
+            return supportedPath + intermediatePath;
+        } else {
+            String parent = Text.getRelativeParent(intermediatePath, 1);
+            while (!parent.isEmpty() && !"/".equals(parent)) {
+                if (Text.isDescendantOrEqual(parent, supportedPath)) {
+                    String relpath = 
intermediatePath.substring(parent.length());
+                    return supportedPath + relpath;
+                }
+                parent = Text.getRelativeParent(parent, 1);
+            }
+            throw new IllegalStateException("Cannot calculate intermediate 
path for service user. Configured Supported path " 
+enforcePrincipalBasedSupportedPath+" has no common ancestor with 
"+intermediatePath);
+        }
+    }
+
     protected @Nullable String computePathWithTypes(@NotNull RepoPath path, 
@NotNull List<VaultPackageAssembler> packageAssemblers) {
         boolean foundType = false;
         String repoinitPath = "/";
diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/EnforceInfo.java
 
b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/EnforceInfo.java
new file mode 100644
index 0000000..dc57f3b
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/EnforceInfo.java
@@ -0,0 +1,29 @@
+/*
+ * 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.accesscontrol;
+
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public interface EnforceInfo {
+
+    boolean enforcePrincipalBased(@NotNull String serviceUserId);
+
+    @NotNull
+    String calculateEnforcedIntermediatePath(@Nullable String 
intermediatePath);
+
+}
\ No newline at end of file
diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractConfigurationEntryHandler.java
 
b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractConfigurationEntryHandler.java
index 22bb540..7d56175 100644
--- 
a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractConfigurationEntryHandler.java
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractConfigurationEntryHandler.java
@@ -29,6 +29,7 @@ import 
org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter
 import org.apache.sling.feature.cpconverter.accesscontrol.AclManager;
 import org.apache.sling.feature.cpconverter.accesscontrol.Mapping;
 import org.apache.sling.feature.cpconverter.features.FeaturesManager;
+import org.apache.sling.feature.cpconverter.repoinit.OperationProcessor;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.osgi.util.converter.Converters;
@@ -98,10 +99,9 @@ abstract class AbstractConfigurationEntryHandler extends 
AbstractRegexEntryHandl
             if (REPOINIT_FACTORY_PID.equals(factoryPid)) {
                 final String[] scripts = 
Converters.standardConverter().convert(configurationProperties.get("scripts")).to(String[].class);
                 if (scripts != null && scripts.length > 0 ) {
-                    for(final String text : scripts) {
-                        if ( text != null && !text.trim().isEmpty() ) {
-                            featuresManager.addOrAppendRepoInitExtension(text, 
runMode);
-                        }
+                    AclManager aclManager = 
Objects.requireNonNull(converter.getAclManager());
+                    for (final String text : scripts) {
+                        aclManager.addRepoinitExtention(text, runMode, 
featuresManager);
                     }
                 }
                 checkReferences(configurationProperties, pid);
diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/handlers/NodeTypesEntryHandler.java
 
b/src/main/java/org/apache/sling/feature/cpconverter/handlers/NodeTypesEntryHandler.java
index 3d0d7c4..7b898f9 100644
--- 
a/src/main/java/org/apache/sling/feature/cpconverter/handlers/NodeTypesEntryHandler.java
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/handlers/NodeTypesEntryHandler.java
@@ -25,6 +25,8 @@ import org.apache.jackrabbit.vault.fs.io.Archive;
 import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
 import org.apache.jackrabbit.vault.util.Constants;
 import 
org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.accesscontrol.AclManager;
+import org.apache.sling.feature.cpconverter.shared.NodeTypeUtil;
 import org.jetbrains.annotations.NotNull;
 
 public class NodeTypesEntryHandler extends AbstractRegexEntryHandler {
@@ -54,19 +56,10 @@ public class NodeTypesEntryHandler extends 
AbstractRegexEntryHandler {
     public void handle(@NotNull String path, @NotNull Archive archive, 
@NotNull Entry entry, @NotNull ContentPackage2FeatureModelConverter converter)
             throws Exception {
         try (BufferedReader reader = new BufferedReader(new 
InputStreamReader(Objects.requireNonNull(archive.openInputStream(entry))))) {
-            
Objects.requireNonNull(converter.getAclManager()).addNodetypeRegistrationSentence("register
 nodetypes");
-            
Objects.requireNonNull(converter.getAclManager()).addNodetypeRegistrationSentence("<<===");
-
-            String nodetypeRegistrationSentence;
-            while ((nodetypeRegistrationSentence = reader.readLine()) != null) 
{
-                if (nodetypeRegistrationSentence.isEmpty()) {
-                    
converter.getAclManager().addNodetypeRegistrationSentence("");
-                } else {
-                    
converter.getAclManager().addNodetypeRegistrationSentence("<< " + 
nodetypeRegistrationSentence);
-                }
+            AclManager aclManager = 
Objects.requireNonNull(converter.getAclManager());
+            for (String line : NodeTypeUtil.generateRepoInitLines(reader)) {
+                aclManager.addNodetypeRegistrationSentence(line);
             }
-
-            converter.getAclManager().addNodetypeRegistrationSentence("===>>");
         }
     }
 
diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/repoinit/AccessControlVisitor.java
 
b/src/main/java/org/apache/sling/feature/cpconverter/repoinit/AccessControlVisitor.java
new file mode 100644
index 0000000..87178b3
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/repoinit/AccessControlVisitor.java
@@ -0,0 +1,198 @@
+/*
+ * 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.repoinit;
+
+import org.apache.sling.feature.cpconverter.accesscontrol.EnforceInfo;
+import org.apache.sling.repoinit.parser.operations.AclLine;
+import org.apache.sling.repoinit.parser.operations.RestrictionClause;
+import org.apache.sling.repoinit.parser.operations.SetAclPaths;
+import org.apache.sling.repoinit.parser.operations.SetAclPrincipalBased;
+import org.apache.sling.repoinit.parser.operations.SetAclPrincipals;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+class AccessControlVisitor extends NoOpVisitor {
+
+    private final Formatter formatter;
+    private final EnforceInfo enforceInfo;
+    private final ConversionMap toConvert;
+    private final Set<String> systemUserIds;
+
+    AccessControlVisitor(@NotNull Formatter formatter, @NotNull EnforceInfo 
enforceInfo,
+                         @NotNull ConversionMap toConvert, @NotNull 
Set<String> systemUserIds) {
+        this.formatter = formatter;
+        this.enforceInfo = enforceInfo;
+        this.toConvert = toConvert;
+        this.systemUserIds = systemUserIds;
+    }
+
+    @Override
+    public void visitSetAclPrincipal(SetAclPrincipals setAclPrincipals) {
+        List<String> principalNames = new 
ArrayList<>(setAclPrincipals.getPrincipals());
+        String optionString = 
getAclOptionsString(setAclPrincipals.getOptions());
+        for (String principalName : setAclPrincipals.getPrincipals()) {
+            if (enforcePrincipalBased(principalName)) {
+                toConvert.putAll(principalName, optionString, 
setAclPrincipals.getLines());
+                principalNames.remove(principalName);
+            }
+        }
+        // re-create original repo-init statements for all principals that 
don't get converted
+        Collection<AclLine> lines = setAclPrincipals.getLines();
+        if (!principalNames.isEmpty() && !lines.isEmpty()) {
+            if (lines.stream().anyMatch(aclLine -> {
+                List<String> paths = aclLine.getProperty(AclLine.PROP_PATHS);
+                return paths == null || paths.isEmpty();
+            })) {
+                generateRepoInit(formatter, "set repository ACL for %s%s%n", 
true, listToString(setAclPrincipals.getPrincipals()), optionString, lines);
+            } else {
+                generateRepoInit(formatter, "set ACL for %s%s%n", true, 
listToString(setAclPrincipals.getPrincipals()), optionString, lines);
+            }
+        }
+    }
+
+    @Override
+    public void visitSetAclPaths(SetAclPaths setAclPaths) {
+        String optionString = getAclOptionsString(setAclPaths.getOptions());
+        List<AclLine> lines = new ArrayList<>();
+        for (AclLine line : setAclPaths.getLines()) {
+            List<String> principalNames = new 
ArrayList<>(line.getProperty(AclLine.PROP_PRINCIPALS));
+            for (String principalName : 
line.getProperty(AclLine.PROP_PRINCIPALS)) {
+                if (enforcePrincipalBased(principalName)) {
+                    AclLine newLine = createAclLine(line, null, 
setAclPaths.getPaths());
+                    toConvert.put(principalName, optionString, newLine);
+                    principalNames.remove(principalName);
+                }
+            }
+
+            if 
(principalNames.equals(line.getProperty(AclLine.PROP_PRINCIPALS))) {
+                // nothing to convert -> use the original line
+                lines.add(line);
+            } else if (!principalNames.isEmpty()) {
+                // re-create modified ACLLine without the principals that will 
be converted
+                AclLine modified = createAclLine(line, principalNames, null);
+                lines.add(modified);
+            }
+        }
+
+        if (!lines.isEmpty()) {
+            generateRepoInit(formatter, "set ACL on %s%s%n", false, 
pathsToString(setAclPaths.getPaths()), optionString, lines);
+        }
+    }
+
+    @Override
+    public void visitSetAclPrincipalBased(SetAclPrincipalBased 
setAclPrincipalBased) {
+        generateRepoInit(formatter, "set principal ACL for %s%s%n", true, 
listToString(setAclPrincipalBased.getPrincipals()), 
getAclOptionsString(setAclPrincipalBased.getOptions()), 
setAclPrincipalBased.getLines());
+    }
+
+    private boolean enforcePrincipalBased(@NotNull String principalName) {
+        return systemUserIds.contains(principalName) && 
enforceInfo.enforcePrincipalBased(principalName);
+    }
+
+    static void generateRepoInit(@NotNull Formatter formatter, @NotNull String 
start, boolean hasPathLines, @NotNull String principalsOrPaths,
+                                 @NotNull String optionString, @NotNull 
Collection<AclLine> lines) {
+        formatter.format(start, principalsOrPaths, optionString);
+        for (AclLine line : lines) {
+            String action = actionToString(line.getAction());
+            String privileges = privilegesToString(line.getAction(), 
line.getProperty(AclLine.PROP_PRIVILEGES));
+            String onOrFor;
+            if (hasPathLines) {
+                String pathStr = 
pathsToString(line.getProperty(AclLine.PROP_PATHS));
+                onOrFor = (pathStr.isEmpty()) ? "" : " on " + pathStr;
+            } else {
+                onOrFor = " for " + 
listToString(line.getProperty(AclLine.PROP_PRINCIPALS));
+            }
+            formatter.format("    %s %s%s%s%s%n", action, privileges, onOrFor,
+                    
nodetypesToString(line.getProperty(AclLine.PROP_NODETYPES)),
+                    restrictionsToString(line.getRestrictions()));
+        }
+        formatter.format("end%n");
+    }
+
+    @NotNull
+    private static AclLine createAclLine(@NotNull AclLine base, @Nullable 
List<String> principalNames, @Nullable List<String> paths) {
+        AclLine al = new AclLine(base.getAction());
+        if (principalNames != null) {
+            al.setProperty(AclLine.PROP_PRINCIPALS, principalNames);
+        }
+        if (paths != null && !paths.isEmpty()) {
+            al.setProperty(AclLine.PROP_PATHS, paths);
+        }
+        al.setProperty(AclLine.PROP_PRIVILEGES, 
base.getProperty(AclLine.PROP_PRIVILEGES));
+        al.setProperty(AclLine.PROP_NODETYPES, 
base.getProperty(AclLine.PROP_NODETYPES));
+        al.setRestrictions(base.getRestrictions());
+        return al;
+    }
+
+    @NotNull
+    private static String getAclOptionsString(@NotNull List<String> options) {
+        return (options.isEmpty()) ? "" : " (ACLOptions="+ 
listToString(options)+")";
+    }
+
+    @NotNull
+    private static String privilegesToString(@NotNull AclLine.Action action, 
@NotNull List<String> privileges) {
+        return (action == AclLine.Action.REMOVE_ALL) ? "*" : 
listToString(privileges);
+    }
+
+    @NotNull
+    private static String pathsToString(@NotNull List<String> paths) {
+        return listToString(paths.stream()
+                .map(s -> {
+                    String homestr = ":home:";
+                    if (s.startsWith(homestr)) {
+                        return "home(" + s.substring(homestr.length(), 
s.lastIndexOf('#')) +")";
+                    } else {
+                        return s;
+                    }
+                })
+                .collect(Collectors.toList()));
+    }
+
+    @NotNull
+    private static String nodetypesToString(@NotNull List<String> nodetypes) {
+        return (nodetypes.isEmpty()) ? "" : " nodetypes " + 
listToString(nodetypes);
+    }
+
+    @NotNull
+    private static String restrictionsToString(@NotNull 
List<RestrictionClause> restrictionClauses) {
+        StringBuilder sb = new StringBuilder();
+        for (RestrictionClause rc : restrictionClauses) {
+            sb.append(" restriction(").append(rc.getName());
+            for (String v : rc.getValues()) {
+                sb.append(",").append(v);
+            }
+            sb.append(')');
+        }
+        return sb.toString();
+    }
+
+    @NotNull
+    private static String actionToString(@NotNull AclLine.Action action) {
+        switch (action) {
+            case DENY: return "deny";
+            case REMOVE: return "remove";
+            case REMOVE_ALL: return "remove";
+            default: return "allow";
+        }
+    }
+}
\ No newline at end of file
diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/repoinit/ConversionMap.java
 
b/src/main/java/org/apache/sling/feature/cpconverter/repoinit/ConversionMap.java
new file mode 100644
index 0000000..65f6694
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/repoinit/ConversionMap.java
@@ -0,0 +1,81 @@
+/*
+ * 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.repoinit;
+
+import org.apache.sling.repoinit.parser.operations.AclLine;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Formatter;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+class ConversionMap {
+
+    private final Map<Key, List<AclLine>> map = new LinkedHashMap<>();
+
+    void put(@NotNull String principalName, @NotNull String options, @NotNull 
AclLine line) {
+        List<AclLine> lineList = map.computeIfAbsent(new Key(principalName, 
options), k -> new ArrayList<>());
+        lineList.add(line);
+    }
+
+    void putAll(@NotNull String principalName, @NotNull String options, 
@NotNull Collection<AclLine> lines) {
+        List<AclLine> lineList = map.computeIfAbsent(new Key(principalName, 
options), k -> new ArrayList<>());
+        lineList.addAll(lines);
+    }
+
+    void generateRepoInit(@NotNull Formatter formatter) {
+        for (Map.Entry<Key, List<AclLine>> entry : map.entrySet()) {
+            String principalName = entry.getKey().principalName;
+            String options = entry.getKey().options;
+            AccessControlVisitor.generateRepoInit(formatter, "set principal 
ACL for %s%s%n", true, principalName, options, entry.getValue());
+        }
+        map.clear();
+    }
+
+    private static final class Key {
+        private final String principalName;
+        private final String options;
+
+        private Key(@NotNull String principalName, @NotNull String options) {
+            this.principalName = principalName;
+            this.options = options;
+        }
+
+        @Override
+        public int hashCode() {
+            return Objects.hash(principalName, options);
+        }
+
+        @Override
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            if (obj instanceof Key) {
+                Key other = (Key) obj;
+                return principalName.equals(other.principalName) && 
options.equals(other.options);
+            } else {
+                return false;
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/repoinit/DefaultVisitor.java
 
b/src/main/java/org/apache/sling/feature/cpconverter/repoinit/DefaultVisitor.java
new file mode 100644
index 0000000..b2e142e
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/repoinit/DefaultVisitor.java
@@ -0,0 +1,198 @@
+/*
+ * 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.repoinit;
+
+import org.apache.jackrabbit.util.ISO8601;
+import org.apache.sling.feature.cpconverter.shared.NodeTypeUtil;
+import org.apache.sling.repoinit.parser.operations.AddGroupMembers;
+import org.apache.sling.repoinit.parser.operations.CreateGroup;
+import org.apache.sling.repoinit.parser.operations.CreatePath;
+import org.apache.sling.repoinit.parser.operations.CreateUser;
+import org.apache.sling.repoinit.parser.operations.DeleteGroup;
+import org.apache.sling.repoinit.parser.operations.DeleteServiceUser;
+import org.apache.sling.repoinit.parser.operations.DeleteUser;
+import org.apache.sling.repoinit.parser.operations.DisableServiceUser;
+import org.apache.sling.repoinit.parser.operations.PathSegmentDefinition;
+import org.apache.sling.repoinit.parser.operations.PropertyLine;
+import org.apache.sling.repoinit.parser.operations.RegisterNamespace;
+import org.apache.sling.repoinit.parser.operations.RegisterNodetypes;
+import org.apache.sling.repoinit.parser.operations.RegisterPrivilege;
+import org.apache.sling.repoinit.parser.operations.RemoveGroupMembers;
+import org.apache.sling.repoinit.parser.operations.SetProperties;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Calendar;
+import java.util.Formatter;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+class DefaultVisitor extends NoOpVisitor {
+
+    private final Formatter formatter;
+
+    DefaultVisitor(@NotNull Formatter formatter) {
+        this.formatter = formatter;
+    }
+
+    @Override
+    public void visitCreateGroup(@NotNull CreateGroup createGroup) {
+        String path = createGroup.getPath();
+        if (path == null || path.isEmpty()) {
+            formatter.format("create group %s%n", createGroup.getGroupname());
+        } else {
+            String forced = (createGroup.isForcedPath()) ? "forced " : "";
+            formatter.format("create group %s with %spath %s%n", 
createGroup.getGroupname(), forced, path);
+        }
+    }
+
+    @Override
+    public void visitDeleteGroup(@NotNull DeleteGroup deleteGroup) {
+        formatter.format("delete group %s%n", deleteGroup.getGroupname());
+    }
+
+    @Override
+    public void visitCreateUser(@NotNull CreateUser createUser) {
+        String path = createUser.getPath();
+        if (path == null || path.isEmpty()) {
+            formatter.format("create user %s%s%n", createUser.getUsername(), 
getPwString(createUser));
+        } else {
+            String forced = (createUser.isForcedPath()) ? "forced " : "";
+            formatter.format("create user %s with %spath %s%s%n", 
createUser.getUsername(), forced, path, getPwString(createUser));
+        }
+    }
+
+    @NotNull
+    private static String getPwString(@NotNull CreateUser createUser) {
+        String pw = createUser.getPassword();
+        if (pw == null || pw.isEmpty()) {
+            return "";
+        } else {
+            String enc = (createUser.getPasswordEncoding() != null) ? 
"{"+createUser.getPasswordEncoding()+"} " :  "";
+            return " with password "+ enc + createUser.getPassword();
+        }
+    }
+
+    @Override
+    public void visitDeleteUser(DeleteUser deleteUser) {
+        formatter.format("delete user %s%n", deleteUser.getUsername());
+    }
+
+    @Override
+    public void visitDeleteServiceUser(DeleteServiceUser deleteServiceUser) {
+        formatter.format("delete service user %s%n", 
deleteServiceUser.getUsername());
+    }
+
+    @Override
+    public void visitCreatePath(CreatePath createPath) {
+        // FIXME: see SLING-10231
+        //        the CreatePath operation doesn't allow to retrieve the 
default primary type
+        //        therefore the generated statement may not be identical to 
the original one.
+        StringBuilder sb = new StringBuilder();
+        for (PathSegmentDefinition psd : createPath.getDefinitions()) {
+            
sb.append("/").append(psd.getSegment()).append("(").append(psd.getPrimaryType());
+            List<String> mixins = psd.getMixins();
+            if (mixins != null && !mixins.isEmpty()) {
+                sb.append(" mixin ").append(listToString(mixins));
+            }
+            sb.append(")");
+        }
+        formatter.format("create path %s%n", sb.toString());
+    }
+
+    @Override
+    public void visitRegisterNamespace(RegisterNamespace registerNamespace) {
+        formatter.format("register namespace ( %s ) %s%n", 
registerNamespace.getPrefix(), registerNamespace.getURI());
+    }
+
+    @Override
+    public void visitRegisterNodetypes(RegisterNodetypes registerNodetypes) {
+        try {
+            for (String nodetypeRegistrationSentence : 
NodeTypeUtil.generateRepoInitLines(new BufferedReader(new 
StringReader(registerNodetypes.getCndStatements())))) {
+                formatter.format("%s%n", nodetypeRegistrationSentence);
+            }
+        } catch (IOException e) {
+            throw new IllegalStateException(e.getMessage());
+        }
+    }
+
+    @Override
+    public void visitRegisterPrivilege(RegisterPrivilege registerPrivilege) {
+        formatter.format("%s%n", registerPrivilege.toString());
+    }
+
+    @Override
+    public void visitDisableServiceUser(DisableServiceUser disableServiceUser) 
{
+        // FIXME : see SLING-10235
+        String reason = disableServiceUser.getParametersDescription();
+        String id = disableServiceUser.getUsername();
+        if (reason.startsWith(id + " : ")) {
+            reason = reason.substring((id + " : ").length());
+        }
+        formatter.format("disable service user %s : \"%s\"%n", 
disableServiceUser.getUsername(), reason);
+
+    }
+
+    @Override
+    public void visitAddGroupMembers(AddGroupMembers addGroupMembers) {
+        formatter.format("add %s to group %s%n", 
listToString(addGroupMembers.getMembers()), addGroupMembers.getGroupname());
+    }
+
+    @Override
+    public void visitRemoveGroupMembers(RemoveGroupMembers removeGroupMembers) 
{
+        formatter.format("remove %s from group %s%n", 
listToString(removeGroupMembers.getMembers()), 
removeGroupMembers.getGroupname());
+    }
+
+    @Override
+    public void visitSetProperties(SetProperties setProperties) {
+        // FIXME: see SLING-10238 for type and quoted values that cannot be 
generated
+        //        exactly as they were originally defined in repo-init
+        formatter.format("set properties on %s%n", 
listToString(setProperties.getPaths()));
+        for (PropertyLine line : setProperties.getPropertyLines()) {
+            String type = (line.getPropertyType()==null) ? "" : 
"{"+line.getPropertyType().name()+"}";
+            String values = valuesToString(line.getPropertyValues(), 
line.getPropertyType());
+            if (line.isDefault()) {
+                formatter.format("default %s%s to %s%n", 
line.getPropertyName(), type, values);
+            } else {
+                formatter.format("set %s%s to %s%n", line.getPropertyName(), 
type, values);
+            }
+        }
+        formatter.format("end%n");
+    }
+
+    private static String valuesToString(@NotNull List<Object> values, 
@Nullable PropertyLine.PropertyType type) {
+        List<String> strings = values.stream()
+                .map(o -> {
+                    if (type == null || type == 
PropertyLine.PropertyType.String) {
+                        String escapequotes = Objects.toString(o, 
"").replace("\"", "\\\"");
+                        return "\"" + escapequotes + "\"";
+                    } else if (type == PropertyLine.PropertyType.Date) {
+                        return "\"" + ISO8601.format((Calendar) o) + "\"";
+                    } else {
+                        return Objects.toString(o, null);
+                    }
+                })
+                .collect(Collectors.toList());
+        return listToString(strings);
+    }
+}
\ No newline at end of file
diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/repoinit/NoOpVisitor.java 
b/src/main/java/org/apache/sling/feature/cpconverter/repoinit/NoOpVisitor.java
new file mode 100644
index 0000000..6bd558d
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/repoinit/NoOpVisitor.java
@@ -0,0 +1,118 @@
+/*
+ * 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.repoinit;
+
+import org.apache.sling.repoinit.parser.operations.AddGroupMembers;
+import org.apache.sling.repoinit.parser.operations.CreateGroup;
+import org.apache.sling.repoinit.parser.operations.CreatePath;
+import org.apache.sling.repoinit.parser.operations.CreateServiceUser;
+import org.apache.sling.repoinit.parser.operations.CreateUser;
+import org.apache.sling.repoinit.parser.operations.DeleteGroup;
+import org.apache.sling.repoinit.parser.operations.DeleteServiceUser;
+import org.apache.sling.repoinit.parser.operations.DeleteUser;
+import org.apache.sling.repoinit.parser.operations.DisableServiceUser;
+import org.apache.sling.repoinit.parser.operations.OperationVisitor;
+import org.apache.sling.repoinit.parser.operations.RegisterNamespace;
+import org.apache.sling.repoinit.parser.operations.RegisterNodetypes;
+import org.apache.sling.repoinit.parser.operations.RegisterPrivilege;
+import org.apache.sling.repoinit.parser.operations.RemoveGroupMembers;
+import org.apache.sling.repoinit.parser.operations.SetAclPaths;
+import org.apache.sling.repoinit.parser.operations.SetAclPrincipalBased;
+import org.apache.sling.repoinit.parser.operations.SetAclPrincipals;
+import org.apache.sling.repoinit.parser.operations.SetProperties;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+abstract class NoOpVisitor implements OperationVisitor {
+
+    static String listToString(@NotNull List<String> list) {
+        if (list.isEmpty()) {
+            return "";
+        } else {
+            return String.join(",", list);
+        }
+    }
+
+    @Override
+    public void visitCreateGroup(CreateGroup createGroup) {
+    }
+
+    @Override
+    public void visitDeleteGroup(DeleteGroup deleteGroup) {
+    }
+
+    @Override
+    public void visitCreateUser(CreateUser createUser) {
+    }
+
+    @Override
+    public void visitDeleteUser(DeleteUser deleteUser) {
+    }
+
+    @Override
+    public void visitCreateServiceUser(CreateServiceUser createServiceUser) {
+    }
+
+    @Override
+    public void visitDeleteServiceUser(DeleteServiceUser deleteServiceUser) {
+    }
+
+    @Override
+    public void visitSetAclPrincipal(SetAclPrincipals setAclPrincipals) {
+    }
+
+    @Override
+    public void visitSetAclPaths(SetAclPaths setAclPaths) {
+    }
+
+    @Override
+    public void visitSetAclPrincipalBased(SetAclPrincipalBased 
setAclPrincipalBased) {
+    }
+
+    @Override
+    public void visitCreatePath(CreatePath createPath) {
+    }
+
+    @Override
+    public void visitRegisterNamespace(RegisterNamespace registerNamespace) {
+    }
+
+    @Override
+    public void visitRegisterNodetypes(RegisterNodetypes registerNodetypes) {
+    }
+
+    @Override
+    public void visitRegisterPrivilege(RegisterPrivilege registerPrivilege) {
+    }
+
+    @Override
+    public void visitDisableServiceUser(DisableServiceUser disableServiceUser) 
{
+    }
+
+    @Override
+    public void visitAddGroupMembers(AddGroupMembers addGroupMembers) {
+    }
+
+    @Override
+    public void visitRemoveGroupMembers(RemoveGroupMembers removeGroupMembers) 
{
+    }
+
+    @Override
+    public void visitSetProperties(SetProperties setProperties) {
+    }
+}
\ No newline at end of file
diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/repoinit/OperationProcessor.java
 
b/src/main/java/org/apache/sling/feature/cpconverter/repoinit/OperationProcessor.java
new file mode 100644
index 0000000..d1e319c
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/repoinit/OperationProcessor.java
@@ -0,0 +1,53 @@
+/*
+ * 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.repoinit;
+
+import org.apache.sling.feature.cpconverter.accesscontrol.EnforceInfo;
+import org.apache.sling.repoinit.parser.operations.Operation;
+import org.apache.sling.repoinit.parser.operations.OperationVisitor;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Formatter;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+public class OperationProcessor {
+
+    // keep track of system users across different 'scripts'
+    private final Set<String> systemUserIds = new LinkedHashSet<>();
+
+    public void apply(@NotNull List<Operation> ops, @NotNull Formatter 
formatter, @NotNull EnforceInfo enforceInfo) {
+        ConversionMap toConvert = new ConversionMap();
+
+        OperationVisitor[] visitors = {
+                new DefaultVisitor(formatter),
+                new SystemUserVisitor(formatter, enforceInfo, systemUserIds),
+                new AccessControlVisitor(formatter, enforceInfo, toConvert, 
systemUserIds)
+        };
+
+        for (Operation op : ops) {
+            for (OperationVisitor v : visitors) {
+                op.accept(v);
+            }
+        }
+
+        // finally generate repo-init statements for acl-statements that are 
recorded as to be
+        // converted to principal-based setup.
+        toConvert.generateRepoInit(formatter);
+    }
+}
\ No newline at end of file
diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/repoinit/SystemUserVisitor.java
 
b/src/main/java/org/apache/sling/feature/cpconverter/repoinit/SystemUserVisitor.java
new file mode 100644
index 0000000..2cad311
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/repoinit/SystemUserVisitor.java
@@ -0,0 +1,52 @@
+/*
+ * 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.repoinit;
+
+import org.apache.sling.feature.cpconverter.accesscontrol.EnforceInfo;
+import org.apache.sling.repoinit.parser.operations.CreateServiceUser;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Formatter;
+import java.util.Set;
+
+class SystemUserVisitor extends NoOpVisitor {
+
+    private final Formatter formatter;
+    private final EnforceInfo enforceInfo;
+    private final Set<String> systemUserIds;
+
+    SystemUserVisitor(@NotNull Formatter formatter, @NotNull EnforceInfo 
enforceInfo, @NotNull Set<String> systemUserIds) {
+        this.formatter = formatter;
+        this.enforceInfo = enforceInfo;
+        this.systemUserIds = systemUserIds;
+    }
+    @Override
+    public void visitCreateServiceUser(CreateServiceUser createServiceUser) {
+        String id = createServiceUser.getUsername();
+        String path = createServiceUser.getPath();
+        systemUserIds.add(id);
+
+        if (enforceInfo.enforcePrincipalBased(id)) {
+            formatter.format("create service user %s with forced path %s%n", 
id, enforceInfo.calculateEnforcedIntermediatePath(path));
+        } else if (path == null || path.isEmpty()) {
+            formatter.format("create service user %s%n", id);
+        } else {
+            String forced = (createServiceUser.isForcedPath()) ? "forced " : 
"";
+            formatter.format("create service user %s with %spath %s%n", id, 
forced, path);
+        }
+    }
+}
\ No newline at end of file
diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/shared/NodeTypeUtil.java 
b/src/main/java/org/apache/sling/feature/cpconverter/shared/NodeTypeUtil.java
new file mode 100644
index 0000000..635ef0f
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/shared/NodeTypeUtil.java
@@ -0,0 +1,47 @@
+/*
+ * 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.shared;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+public final class NodeTypeUtil {
+
+    private NodeTypeUtil() {}
+
+    public static List<String> generateRepoInitLines(@NotNull BufferedReader 
rawLines) throws IOException {
+        List<String> lines = new ArrayList<>();
+        lines.add("register nodetypes");
+        lines.add("<<===");
+
+        String raw;
+        while((raw = rawLines.readLine()) != null) {
+            if (raw.isEmpty()) {
+                lines.add("");
+            } else {
+                lines.add("<< "+raw);
+            }
+        }
+        lines.add("===>>");
+        return lines;
+    }
+
+}
\ No newline at end of file
diff --git 
a/src/test/java/org/apache/sling/feature/cpconverter/handlers/ConfigurationEntryHandlerTest.java
 
b/src/test/java/org/apache/sling/feature/cpconverter/handlers/ConfigurationEntryHandlerTest.java
index 849f259..2b2bac3 100644
--- 
a/src/test/java/org/apache/sling/feature/cpconverter/handlers/ConfigurationEntryHandlerTest.java
+++ 
b/src/test/java/org/apache/sling/feature/cpconverter/handlers/ConfigurationEntryHandlerTest.java
@@ -43,6 +43,7 @@ import org.apache.sling.feature.Extension;
 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.Mapping;
 import org.apache.sling.feature.cpconverter.features.DefaultFeaturesManager;
 import org.apache.sling.feature.cpconverter.features.FeaturesManager;
@@ -157,7 +158,7 @@ public class ConfigurationEntryHandlerTest {
         when(featuresManager.getRunMode(anyString())).thenReturn(feature);
         ContentPackage2FeatureModelConverter converter = 
mock(ContentPackage2FeatureModelConverter.class);
         when(converter.getFeaturesManager()).thenReturn(featuresManager);
-        AclManager aclManager = mock(AclManager.class);
+        AclManager aclManager = spy(new DefaultAclManager());
         when(converter.getAclManager()).thenReturn(aclManager);
 
         configurationEntryHandler.handle(resourceConfiguration, archive, 
entry, converter);
diff --git 
a/src/test/java/org/apache/sling/feature/cpconverter/handlers/RepoInitTest.java 
b/src/test/java/org/apache/sling/feature/cpconverter/handlers/RepoInitTest.java
new file mode 100644
index 0000000..3138470
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/feature/cpconverter/handlers/RepoInitTest.java
@@ -0,0 +1,201 @@
+/*
+ * 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 com.google.common.collect.Lists;
+import org.apache.jackrabbit.vault.fs.io.Archive;
+import org.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Configuration;
+import org.apache.sling.feature.Configurations;
+import org.apache.sling.feature.Extension;
+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.Mapping;
+import org.apache.sling.feature.cpconverter.features.DefaultFeaturesManager;
+import org.apache.sling.feature.cpconverter.features.FeaturesManager;
+import org.apache.sling.feature.cpconverter.repoinit.OperationProcessor;
+import org.apache.sling.feature.io.json.ConfigurationJSONWriter;
+import org.apache.sling.repoinit.parser.impl.RepoInitParserService;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.Collection;
+import java.util.Dictionary;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(Parameterized.class)
+public class RepoInitTest {
+
+    private static final String REPOINIT_PID = 
"org.apache.sling.jcr.repoinit.RepositoryInitializer";
+    private static final String PATH_PREFIX = 
"/jcr_root/apps/asd/config.publish/" + REPOINIT_PID;
+
+    private static final String REPOINIT_CONVERSION_PATH = 
"/jcr_root/apps/asd/config.publish/" + REPOINIT_PID + "-conversion-test.config";
+
+    private final AbstractConfigurationEntryHandler configurationEntryHandler;
+    private final boolean enforcePrincipalBasedAcSetup;
+    private final String enforcedPath;
+
+    private final String name;
+
+    @Parameterized.Parameters(name = "name={1}")
+    public static Collection<Object[]> parameters() {
+        return Lists.newArrayList(
+                new Object[] { true, "Enforce principal-based ac setup" },
+                new Object[] { false, "Don't enforce principal-based ac setup" 
});
+    };
+
+    public RepoInitTest(boolean enforcePrincipalBasedAcSetup, String name) {
+        this.configurationEntryHandler = new ConfigurationEntryHandler();
+        this.enforcePrincipalBasedAcSetup = enforcePrincipalBasedAcSetup;
+        this.enforcedPath = (enforcePrincipalBasedAcSetup) ? 
"/home/users/system/cq:services" : null;
+        this.name = name;
+    }
+
+    @Test
+    public void parseConversionRepoInit() throws Exception {
+        String path = PATH_PREFIX + "-conversion-test.config";
+        String result = PATH_PREFIX + "-conversion-result.config";
+
+        Extension expectedExtension;
+        if (enforcePrincipalBasedAcSetup) {
+            expectedExtension = extractExtentions(result, false, false);
+        } else {
+            expectedExtension = extractExtentions(path, false, false);
+        }
+        Extension extension = extractExtentions(path, 
enforcePrincipalBasedAcSetup, false);
+        assertNotNull(expectedExtension);
+        assertNotNull(extension);
+        String txt = extension.getText();
+        assertEquals(name, expectedExtension.getText().trim(), txt.trim());
+
+        // verify that the generated repo-init is valid
+        assertFalse(name, new RepoInitParserService().parse(new 
StringReader(txt)).isEmpty());
+    }
+
+    @Test
+    public void parseConversionOmittedForServiceUserRepoInit() throws 
Exception {
+        String path = PATH_PREFIX + "-conversion-test.config";
+
+        Extension expectedExtension = extractExtentions(path, false, true);
+        Extension extension = extractExtentions(path, 
enforcePrincipalBasedAcSetup, true);
+        assertNotNull(expectedExtension);
+        assertNotNull(extension);
+        String txt = extension.getText();
+        assertEquals(name, expectedExtension.getText().trim(), txt.trim());
+
+        // verify that the generated repo-init is valid
+        assertFalse(name, new RepoInitParserService().parse(new 
StringReader(txt)).isEmpty());
+    }
+
+    @Test
+    public void parseNoConversionRepoInit() throws Exception {
+        String path = PATH_PREFIX + "-no-conversion-test.config";
+
+        Extension expectedExtension = extractExtentions(path, false, false);
+        Extension extension = extractExtentions(path, 
enforcePrincipalBasedAcSetup, false);
+        assertNotNull(expectedExtension);
+        assertNotNull(extension);
+        String txt = extension.getText();
+        assertEquals(name, expectedExtension.getText().trim(), txt.trim());
+
+        // verify that the generated repo-init is valid
+        assertFalse(name, new RepoInitParserService().parse(new 
StringReader(txt)).isEmpty());
+    }
+
+    @Test
+    public void parseNoConversionWithDiffRepoInit() throws Exception {
+        // NOTE: create-path statements with default primary type and 
set-property cannot be converted 1:1
+        // See SLING-10231, SLING-10238 and FIXMEs in DefaultVisitor
+        String path = PATH_PREFIX + "-no-conv-with-diff.config";
+
+        String resultTxt = "create path /test(sling:Folder)/a(nt:folder mixin 
mix:referenceable,mix:shareable)/b(nt:unstructured)/c(sling:Folder mixin 
mix:created)\n"+
+        "create path /test(sling:Folder)/a(nt:folder mixin 
mix:referenceable,mix:shareable)/b(nt:unstructured)/c(sling:Folder mixin 
mix:created)\n"+
+        " set properties on /test\n"+
+        "set testprop{String} to \"one=two\"\n"+
+        "set testprop{String} to \"\\\"one=two\\\"\"\n"+
+        "set sling:ResourceType{String} to \"/x/y/z\"\n"+
+        "default someInteger{Long} to 42\n"+
+        "set someFlag{Boolean} to true\n"+
+        "default someDate{Date} to \"2020-03-19T11:39:33.437+05:30\"\n"+
+        "set quotedMix{String} to \"quoted\",\"non-quoted\",\"the last \\\" 
one\"\n"+
+        "set aStringMultiValue{String} to \"one\",\"two\",\"three\"\n"+
+        "set aLongMultiValue{Long} to 1,2,3\n"+
+        "set curlyBracketsAndDoubleQuotes{String} to \"{\\\"one, 
two\\\":\\\"three, four\\\"}\"\n"+
+        "set curlyBracketsAndSingleQuotes{String} to \"{'five, 
six':'seven,eight'}\"\n"+
+        "end";
+        Extension extension = extractExtentions(path, 
enforcePrincipalBasedAcSetup, false);
+        assertNotNull(extension);
+        String expectedTxt = (enforcePrincipalBasedAcSetup) ? resultTxt : 
extractExtentions(path, false, false).getText();
+        String txt = extension.getText();
+        assertEquals(name, expectedTxt, txt.trim());
+
+        // verify that the generated repo-init is valid
+        assertFalse(name, new RepoInitParserService().parse(new 
StringReader(txt)).isEmpty());
+    }
+
+    private Extension extractExtentions(@NotNull String path, boolean 
enforcePrincipalBasedAcSetup, boolean addMappingById) throws Exception {
+        Archive archive = mock(Archive.class);
+        Archive.Entry entry = mock(Archive.Entry.class);
+
+        when(entry.getName()).thenReturn(path.substring(path.lastIndexOf('/') 
+ 1));
+        
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);
+        doCallRealMethod().when(featuresManager).addConfiguration(anyString(), 
anyString(), anyString(), any());
+        when(featuresManager.getRunMode(anyString())).thenReturn(feature);
+
+        AclManager aclManager = spy(new 
DefaultAclManager((enforcePrincipalBasedAcSetup) ? enforcedPath : null));
+        if (addMappingById) {
+            aclManager.addMapping(new 
Mapping("org.apache.sling.testbundle:sub1=su1"));
+            aclManager.addMapping(new 
Mapping("org.apache.sling.testbundle:sub2=su2"));
+            aclManager.addMapping(new 
Mapping("org.apache.sling.testbundle:sub3=su3"));
+            aclManager.addMapping(new 
Mapping("org.apache.sling.testbundle=su-second-script"));
+        }
+
+        ContentPackage2FeatureModelConverter converter = 
mock(ContentPackage2FeatureModelConverter.class);
+        when(converter.getFeaturesManager()).thenReturn(featuresManager);
+        when(converter.getAclManager()).thenReturn(aclManager);
+
+        configurationEntryHandler.handle(path, archive, entry, converter);
+        return 
featuresManager.getRunMode("publish").getExtensions().getByName(Extension.EXTENSION_NAME_REPOINIT);
+    }
+
+}
\ No newline at end of file
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.jcr.repoinit.RepositoryInitializer-conversion-result.config
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.jcr.repoinit.RepositoryInitializer-conversion-result.config
new file mode 100644
index 0000000..357d76b
--- /dev/null
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.jcr.repoinit.RepositoryInitializer-conversion-result.config
@@ -0,0 +1,45 @@
+# 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.
+scripts=[\
+"
+create service user su1 with forced path /home/users/system/cq:services
+create service user su2 with forced path 
/home/users/system/cq:services/myfeature
+create service user su3 with forced path 
/home/users/system/cq:services/myfeature/subtree
+set principal ACL for su1
+    allow jcr:read,jcr:modifyProperties on /conf,/content 
restriction(rep:glob,*)
+    allow jcr:read on /conf,/content 
restriction(rep:itemNames,jcr:primaryType,jcr:mixinTypes) 
restriction(rep:ntNames,nt:folder)
+    remove * on /apps
+    allow jcr:read,jcr:write on /conf,/libs,:repository,home(su1)
+end
+set principal ACL for su2 
(ACLOptions\=someOption,someOtherOption,namespaced:option)
+    remove jcr:lockManagement on /content nodetypes nt:folder
+    remove * on :repository,home(su1)
+end
+set principal ACL for su2
+    allow jcr:read,jcr:write on /conf,/libs,:repository,home(su1)
+end
+set principal ACL for su3
+    deny jcr:versionManagement on /conf,/libs,:repository,home(su1) 
restriction(rep:glob,/subtree)
+    remove jcr:modifyProperties on /conf,/libs,:repository,home(su1)
+end",\
+"
+create service user su-second-script with forced path 
/home/users/system/cq:services
+set principal ACL for su1
+    allow jcr:read on /second-script
+end
+set principal ACL for su-second-script
+    allow jcr:read on /second-script
+end"\
+]
\ No newline at end of file
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.jcr.repoinit.RepositoryInitializer-conversion-test.config
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.jcr.repoinit.RepositoryInitializer-conversion-test.config
new file mode 100644
index 0000000..6d700d4
--- /dev/null
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.jcr.repoinit.RepositoryInitializer-conversion-test.config
@@ -0,0 +1,39 @@
+# 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.
+scripts=[\
+"
+create service user su1
+create service user su2 with path system/myfeature
+set ACL for su1
+    allow jcr:read,jcr:modifyProperties on /conf,/content 
restriction(rep:glob,*)
+    allow jcr:read on /conf,/content 
restriction(rep:itemNames,jcr:primaryType,jcr:mixinTypes) 
restriction(rep:ntNames,nt:folder)
+    remove * on /apps
+end
+set ACL for su2 (ACLOptions\=someOption,someOtherOption,namespaced:option)
+    remove jcr:lockManagement on /content nodetypes nt:folder
+    remove * on :repository,home(su1)
+end
+create service user su3 with forced path /home/users/system/myfeature/subtree
+set ACL on /conf,/libs,:repository,home(su1)
+    allow jcr:read,jcr:write for su1,su2
+    deny jcr:versionManagement for su3 restriction(rep:glob,/subtree)
+    remove jcr:modifyProperties for su3
+end",\
+"
+create service user su-second-script
+set ACL on /second-script
+    allow jcr:read for su1,su-second-script
+end"
+]
\ No newline at end of file
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.jcr.repoinit.RepositoryInitializer-no-conv-with-diff.config
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.jcr.repoinit.RepositoryInitializer-no-conv-with-diff.config
new file mode 100644
index 0000000..73b51b8
--- /dev/null
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.jcr.repoinit.RepositoryInitializer-no-conv-with-diff.config
@@ -0,0 +1,34 @@
+# 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.
+scripts=[\
+"
+create path /test(sling:Folder)/a(nt:folder mixin 
mix:referenceable,mix:shareable)/b(nt:unstructured)/c(sling:Folder mixin 
mix:created)
+create path (sling:Folder) /test/a(nt:folder mixin 
mix:referenceable,mix:shareable)/b(nt:unstructured)/c(mixin mix:created)
+",\
+"
+set properties on /test
+   set testprop to \"one\=two\"
+   set testprop to \"\\\"one\=two\\\"\"
+   set sling:ResourceType{String} to /x/y/z
+   default someInteger{Long} to 42
+   set someFlag{Boolean} to true
+   default someDate{Date} to \"2020-03-19T11:39:33.437+05:30\"
+   set quotedMix to \"quoted\", non-quoted, \"the last \\\" one\"
+   set aStringMultiValue to \"one\",\"two\",\"three\"
+   set aLongMultiValue{Long} to 1,2,3
+   set curlyBracketsAndDoubleQuotes{String} to \"{\\\"one, two\\\":\\\"three, 
four\\\"}\"
+   set curlyBracketsAndSingleQuotes{String} to \"{'five, six':'seven,eight'}\"
+end"\
+]
\ No newline at end of file
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.jcr.repoinit.RepositoryInitializer-no-conversion-test.config
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.jcr.repoinit.RepositoryInitializer-no-conversion-test.config
new file mode 100644
index 0000000..e662e39
--- /dev/null
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.jcr.repoinit.RepositoryInitializer-no-conversion-test.config
@@ -0,0 +1,72 @@
+# 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.
+scripts=[\
+"
+create service user su with forced path 
/home/users/system/cq:services/myfeature
+set principal ACL for su
+    allow jcr:all on /var restriction(rep:ntNames,nt:unstructured)
+end",\
+"
+create group gr1 with path my/group/path
+set repository ACL for gr1
+    allow jcr:namespaceManagement,jcr:nodeTypeDefinitionManagement
+end",\
+"
+set ACL on /conf,/content
+    allow jcr:read,jcr:modifyProperties for gr1 restriction(rep:glob,*)
+    allow jcr:read for gr1 
restriction(rep:itemNames,jcr:primaryType,jcr:mixinTypes) 
restriction(rep:ntNames\,nt:folder)
+end",\
+"
+set ACL for gr1 (ACLOptions\=someOption,someOtherOption,namespaced:option)
+    deny jcr:versionManagement on /content nodetypes nt:folder 
restriction(rep:glob,/subtree)
+    remove jcr:lockManagement on /content
+    remove * on :repository,home(gr1)
+end",\
+"
+create group gr2 with forced path /home/groups/myfeature
+set ACL on /conf,/libs
+    allow jcr:read,jcr:write for gr1,gr2 restriction(rep:glob,/subtree)
+    remove jcr:modifyProperties for gr2
+end",\
+"
+create group gr3
+create user a
+create user b with path myfeature
+create user c with forced path /home/users/bla with password plaintext
+create user d with password {SHA-256} 
dc460da4ad72c482231e28e688e01f2778a88ce31a08826899d54ef7183998b5
+add a,b,c,d to group gr3
+remove a,b from group gr1
+disable service user deprecated_service_user : \"Disabled user to make an 
example\"
+delete service user deprecated_service_user
+delete user c
+delete group gr1",\
+"
+create path /test(sling:Folder)/a(nt:folder mixin 
mix:referenceable,mix:shareable)/b(nt:unstructured)/c(sling:Folder mixin 
mix:created)
+",\
+"
+register namespace ( prefix ) http://prefix/v0.0.0",\
+"register nodetypes
+<<\=\=\=
+<<  <slingevent\=\'http://sling.apache.org/jcr/event/1.0\'>
+<<  [slingevent:Event] > nt:unstructured, nt:hierarchyNode
+<<    - slingevent:topic (string)
+<<    - slingevent:properties (binary)
+\=\=\=>>",\
+"
+register abstract privilege privAbstract
+register privilege priv1
+register privilege priv2 with privAbstract,priv1"\
+]
+

Reply via email to