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

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

commit b2a910911e125a4546ba9d1146f91bd042e0e548
Author: angela <[email protected]>
AuthorDate: Fri Jan 15 08:05:49 2021 +0100

    SLING-9692 : Add support for principal-based access control entries
---
 .../accesscontrol/AccessControlEntry.java          |  13 ++
 .../accesscontrol/DefaultAclManager.java           |  15 ++
 ...ntentPackage2FeatureModelConverterLauncher.java |   8 +-
 .../cpconverter/handlers/AbstractPolicyParser.java |   2 +-
 .../handlers/RepPrincipalPolicyEntryHandler.java   | 121 +++++++++++++++
 ...sling.feature.cpconverter.handlers.EntryHandler |   1 +
 .../accesscontrol/EnforcePrincipalBasedTest.java   | 163 ++++++++++++++++++++
 .../feature/cpconverter/handlers/ParseResult.java  |  22 +++
 .../handlers/RepPolicyEntryHandlerTest.java        |  35 +----
 .../RepPrincipalPolicyEntryHandlerTest.java        | 164 +++++++++++++++++++++
 .../services/random1/_rep_principalPolicy.xml      |  26 ++++
 .../services/random2/_rep_principalPolicy.xml      |  29 ++++
 .../services/random3/_rep_principalPolicy.xml      |  26 ++++
 .../services/random4/_rep_principalPolicy.xml      |  26 ++++
 14 files changed, 616 insertions(+), 35 deletions(-)

diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AccessControlEntry.java
 
b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AccessControlEntry.java
index 95151c4..984e7f3 100644
--- 
a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AccessControlEntry.java
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/AccessControlEntry.java
@@ -36,10 +36,17 @@ public final class AccessControlEntry {
 
     private final List<String> restrictions = new LinkedList<>();
 
+    private final boolean isPrincipalBased;
+
     public AccessControlEntry(boolean isAllow, @NotNull String privileges, 
@NotNull RepoPath repositoryPath) {
+        this(isAllow, privileges, repositoryPath, false);
+    }
+
+    public AccessControlEntry(boolean isAllow, @NotNull String privileges, 
@NotNull RepoPath repositoryPath, boolean isPrincipalBased) {
         this.isAllow = isAllow;
         this.privileges = privileges;
         this.repositoryPath = repositoryPath;
+        this.isPrincipalBased = isPrincipalBased;
     }
 
     public void addRestriction(@Nullable String restriction) {
@@ -64,6 +71,10 @@ public final class AccessControlEntry {
         return restrictions;
     }
 
+    public boolean isPrincipalBased() {
+        return isPrincipalBased;
+    }
+
     @Override
     public String toString() {
         return "Acl [isAllow="
@@ -74,6 +85,8 @@ public final class AccessControlEntry {
                + repositoryPath
                + ", restrictions="
                + restrictions
+               + ", isPrincipalBased="
+               + isPrincipalBased
                + "]";
     }
 
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 90c2277..76c5468 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
@@ -51,6 +51,9 @@ public final class DefaultAclManager implements AclManager {
 
     private static final String CONTENT_XML_FILE_NAME = ".content.xml";
 
+    private final boolean enforcePrincipalBased;
+    private RepoPath supportedPrincipalBasedPath;
+
     private final Set<SystemUser> systemUsers = new LinkedHashSet<>();
     private final Set<Group> groups = new LinkedHashSet<>();
     private final Set<User> users = new LinkedHashSet<>();
@@ -61,6 +64,15 @@ public final class DefaultAclManager implements AclManager {
 
     private volatile PrivilegeDefinitions privilegeDefinitions;
 
+    public DefaultAclManager() {
+        this(false, null);
+    }
+    public DefaultAclManager(boolean enforcePrincipalBased, @Nullable String 
supportedPrincipalBasedPath) {
+        this.enforcePrincipalBased = enforcePrincipalBased;
+        this.supportedPrincipalBasedPath = (supportedPrincipalBasedPath == 
null) ? null : new RepoPath(supportedPrincipalBasedPath);
+    }
+
+
     @Override
     public boolean addUser(@NotNull User user) {
         return users.add(user);
@@ -118,6 +130,7 @@ public final class DefaultAclManager implements AclManager {
                 }
             }
 
+            // TODO: paths only should/need to be create with resource-based 
access control
             Set<RepoPath> paths = acls.entrySet().stream()
                     .filter(entry -> getSystemUser(entry.getKey()).isPresent())
                     .map(Entry::getValue)
@@ -136,6 +149,8 @@ public final class DefaultAclManager implements AclManager {
                             path -> formatter.format("create path %s%n", path)
                     );
 
+            // TODO: generate 2 set of access control entries: principal-based 
und resource-based.
+            // TODO: if 'enforce-principal-based' is turned on all entries 
should be generated as prinicpal-based
             // add the acls
             acls.forEach((systemUserID, authorizations) ->
                 getSystemUser(systemUserID).ifPresent(systemUser ->
diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/cli/ContentPackage2FeatureModelConverterLauncher.java
 
b/src/main/java/org/apache/sling/feature/cpconverter/cli/ContentPackage2FeatureModelConverterLauncher.java
index bc2d44b..8e778f6 100644
--- 
a/src/main/java/org/apache/sling/feature/cpconverter/cli/ContentPackage2FeatureModelConverterLauncher.java
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/cli/ContentPackage2FeatureModelConverterLauncher.java
@@ -96,6 +96,12 @@ public final class 
ContentPackage2FeatureModelConverterLauncher implements Runna
     @Option(names = { "-Z", "--fail-on-mixed-packages" }, description = "Fail 
the conversion if the resulting attached content-package is MIXED type", 
required = false)
     private boolean failOnMixedPackages = false;
 
+    @Option(names = { "--enforce-principal-based" }, description = "Converts 
all service user access control entries to principal-based setup", required = 
false)
+    private boolean enforcePrincipalBased = false;
+
+    @Option(names = { "--supported-principal-based-path" }, description = 
"Path supported for principal-based access control setup", required = false)
+    private String supportedPrincipalBasedPath = null;
+
     @Override
     public void run() {
         if (quiet) {
@@ -143,7 +149,7 @@ public final class 
ContentPackage2FeatureModelConverterLauncher implements Runna
                                                              
.setFeaturesManager(featuresManager)
                                                              
.setBundlesDeployer(new DefaultArtifactsDeployer(artifactsOutputDirectory))
                                                              
.setEntryHandlersManager(new DefaultEntryHandlersManager())
-                                                             
.setAclManager(new DefaultAclManager())
+                                                             
.setAclManager(new DefaultAclManager(enforcePrincipalBased, 
supportedPrincipalBasedPath))
                                                              
.setEmitter(DefaultPackagesEventsEmitter.open(featureModelsOutputDirectory))
                                                              
.setFailOnMixedPackages(failOnMixedPackages)
                                                              
.setDropContent(true);
diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractPolicyParser.java
 
b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractPolicyParser.java
index fd68b31..31cd85e 100644
--- 
a/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractPolicyParser.java
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/handlers/AbstractPolicyParser.java
@@ -56,7 +56,7 @@ abstract class AbstractPolicyParser extends 
AbstractJcrNodeParser<Boolean> {
         this.aclManager = aclManager;
     }
 
-    private static @Nullable String extractValue(@Nullable String expression) {
+    static @Nullable String extractValue(@Nullable String expression) {
         if (expression == null || expression.isEmpty()) {
             return expression;
         }
diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/handlers/RepPrincipalPolicyEntryHandler.java
 
b/src/main/java/org/apache/sling/feature/cpconverter/handlers/RepPrincipalPolicyEntryHandler.java
new file mode 100644
index 0000000..a3c276b
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/handlers/RepPrincipalPolicyEntryHandler.java
@@ -0,0 +1,121 @@
+/*
+ * 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.accesscontrol.AccessControlEntry;
+import org.apache.sling.feature.cpconverter.accesscontrol.AclManager;
+import org.apache.sling.feature.cpconverter.shared.RepoPath;
+import org.jetbrains.annotations.NotNull;
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import javax.xml.transform.sax.TransformerHandler;
+import java.util.Stack;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
+
+public final class RepPrincipalPolicyEntryHandler extends 
AbstractPolicyEntryHandler {
+
+    public RepPrincipalPolicyEntryHandler() {
+        super("/jcr_root(.*/)_rep_principalPolicy.xml");
+    }
+
+    @Override
+    @NotNull AbstractPolicyParser createPolicyParser(@NotNull RepoPath 
repositoryPath, @NotNull AclManager aclManager, @NotNull TransformerHandler 
handler) {
+        return new RepPrincipalPolicyParser(repositoryPath,
+                aclManager,
+                handler);
+    }
+
+    private static final class RepPrincipalPolicyParser extends 
AbstractPolicyParser {
+
+        private static final String REP_RESTRICTIONS = "rep:Restrictions";
+
+        private static final String REP_PRINCIPAL_NAME = "rep:principalName";
+
+        private static final String REP_PRIVILEGES = "rep:privileges";
+
+        private static final String REP_PRINCIPAL_POLICY = 
"rep:PrincipalPolicy";
+
+        private static final String REP_PRINCIPAL_ENTRY = "rep:PrincipalEntry";
+
+        private static final String REP_EFFECTIVE_PATH = "rep:effectivePath";
+
+        private final Stack<AccessControlEntry> aces = new Stack<>();
+
+        private boolean processCurrentAcl = false;
+
+        private String principalName = null;
+
+        public RepPrincipalPolicyParser(RepoPath repositoryPath, AclManager 
aclManager, TransformerHandler handler) {
+            super(REP_PRINCIPAL_POLICY, repositoryPath, aclManager, handler);
+        }
+
+        @Override
+        protected void onJcrRootElement(String uri, String localName, String 
qName, Attributes attributes) {
+            super.onJcrRootElement(uri, localName, qName, attributes);
+            principalName = attributes.getValue(REP_PRINCIPAL_NAME);
+        }
+
+        @Override
+        public void startElement(String uri, String localName, String qName, 
Attributes attributes)
+                throws SAXException {
+            if (onRepAclNode) {
+                String primaryType = attributes.getValue(JCR_PRIMARYTYPE);
+                if (REP_PRINCIPAL_ENTRY.equals(primaryType)) {
+                    if (principalName == null) {
+                        throw new IllegalStateException("isolated 
principal-based access control entry. no principal found.");
+                    }
+                    String privileges = 
extractValue(attributes.getValue(REP_PRIVILEGES));
+                    RepoPath effectivePath = new 
RepoPath(attributes.getValue(REP_EFFECTIVE_PATH));
+
+                    AccessControlEntry ace = new AccessControlEntry(true, 
privileges, effectivePath, true);
+
+                    processCurrentAcl = aclManager.addAcl(principalName, ace);
+                    if (processCurrentAcl) {
+                        aces.add(ace);
+                    } else {
+                        hasRejectedNodes = true;
+                    }
+                } else if (REP_RESTRICTIONS.equals(primaryType) && 
!aces.isEmpty()) {
+                    if (processCurrentAcl) {
+                        AccessControlEntry ace = aces.peek();
+                        aces.add(ace);
+                        addRestrictions(ace, attributes);
+                    }
+                }
+            } else {
+                super.startElement(uri, localName, qName, attributes);
+            }
+
+            if (!onRepAclNode || !processCurrentAcl) {
+                handler.startElement(uri, localName, qName, attributes);
+            }
+        }
+
+        @Override
+        public void endElement(String uri, String localName, String qName) 
throws SAXException {
+            if (onRepAclNode && processCurrentAcl && !aces.isEmpty()) {
+                aces.pop();
+            } else {
+                processCurrentAcl = false;
+                principalName = null;
+                handler.endElement(uri, localName, qName);
+            }
+        }
+    }
+}
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 7a82e4e..46fb089 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
@@ -7,6 +7,7 @@ 
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.RepPrincipalPolicyEntryHandler
 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/EnforcePrincipalBasedTest.java
 
b/src/test/java/org/apache/sling/feature/cpconverter/accesscontrol/EnforcePrincipalBasedTest.java
new file mode 100644
index 0000000..a7dc3fa
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/feature/cpconverter/accesscontrol/EnforcePrincipalBasedTest.java
@@ -0,0 +1,163 @@
+/*
+ * 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.apache.sling.feature.ArtifactId;
+import org.apache.sling.feature.Extension;
+import org.apache.sling.feature.Feature;
+import org.apache.sling.feature.cpconverter.features.DefaultFeaturesManager;
+import org.apache.sling.feature.cpconverter.features.FeaturesManager;
+import org.apache.sling.feature.cpconverter.shared.RepoPath;
+import org.apache.sling.feature.cpconverter.vltpkg.VaultPackageAssembler;
+import org.apache.sling.repoinit.parser.RepoInitParser;
+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.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.io.File;
+import java.io.StringReader;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class EnforcePrincipalBasedTest {
+
+    private final SystemUser systemUser = new SystemUser("user1", new 
RepoPath("/home/users/system/intermediate/usernode"), new 
RepoPath("/home/users/system/intermediate"));
+
+    private AclManager aclManager;
+    private Path tempDir;
+
+    private VaultPackageAssembler assembler;
+    private FeaturesManager fm;
+    private Feature feature;
+
+    @Before
+    public void setUp() throws Exception {
+        aclManager = new DefaultAclManager(true, 
"/home/users/system/cq:services");
+        tempDir = Files.createTempDirectory(getClass().getSimpleName());
+
+        assembler = mock(VaultPackageAssembler.class);
+        when(assembler.getEntry(anyString())).thenReturn(new 
File(System.getProperty("java.io.tmpdir")));
+        feature = new Feature(new ArtifactId("org.apache.sling", 
"org.apache.sling.cp2fm", "0.0.1", null, null));
+
+        fm = Mockito.spy(new DefaultFeaturesManager(tempDir.toFile()));
+        when(fm.getTargetFeature()).thenReturn(feature);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        aclManager = null;
+
+        // Delete the temp dir again
+        Files.walk(tempDir)
+                .sorted(Comparator.reverseOrder())
+                .map(Path::toFile)
+                .forEach(File::delete);
+    }
+
+    @Test
+    public void testResourceBasedConversion() throws RepoInitParsingException {
+        aclManager.addSystemUser(systemUser);
+
+        RepoPath accessControlledPath = new RepoPath("/content/feature");
+        aclManager.addAcl("user1", new AccessControlEntry(true, "jcr:read", 
accessControlledPath , false));
+
+        aclManager.addRepoinitExtension(Arrays.asList(assembler), fm);
+
+        Extension repoinitExtension = 
feature.getExtensions().getByName(Extension.EXTENSION_NAME_REPOINIT);
+        assertNotNull(repoinitExtension);
+
+        String expected =
+                "create service user user1 with path 
/home/users/system/cq:services/intermediate" + System.lineSeparator() +
+                "set principal ACL for user1" + System.lineSeparator() +
+                "allow jcr:read on /content/feature" + System.lineSeparator() +
+                "end" + System.lineSeparator();
+
+        String actual = repoinitExtension.getText();
+        assertEquals(expected, actual);
+
+        RepoInitParser repoInitParser = new RepoInitParserService();
+        List<Operation> operations = repoInitParser.parse(new 
StringReader(actual));
+        assertFalse(operations.isEmpty());
+    }
+
+    @Test
+    public void testPrincipalBased() throws RepoInitParsingException {
+        aclManager.addSystemUser(systemUser);
+
+        RepoPath accessControlledPath = new RepoPath("/content/feature");
+        aclManager.addAcl("user1", new AccessControlEntry(true, "jcr:read", 
accessControlledPath, true));
+
+        aclManager.addRepoinitExtension(Arrays.asList(assembler), fm);
+
+        Extension repoinitExtension = 
feature.getExtensions().getByName(Extension.EXTENSION_NAME_REPOINIT);
+        assertNotNull(repoinitExtension);
+
+        String expected =
+                "create service user user1 with path 
/home/users/system/cq:services/intermediate" + System.lineSeparator() +
+                        "set principal ACL for user1" + System.lineSeparator() 
+
+                        "allow jcr:read on /content/feature" + 
System.lineSeparator() +
+                        "end" + System.lineSeparator();
+
+        String actual = repoinitExtension.getText();
+        assertEquals(expected, actual);
+
+        RepoInitParser repoInitParser = new RepoInitParserService();
+        List<Operation> operations = repoInitParser.parse(new 
StringReader(actual));
+        assertFalse(operations.isEmpty());
+    }
+
+    @Test
+    public void testPrincipalBasedForUserHome() throws 
RepoInitParsingException {
+        aclManager.addSystemUser(systemUser);
+
+        RepoPath accessControlledPath = new 
RepoPath("/home/users/system/cq:services/intermediate/usernode");
+        AccessControlEntry acl = new AccessControlEntry(true, "jcr:read", 
accessControlledPath, true);
+        aclManager.addAcl("user1", acl);
+
+        aclManager.addRepoinitExtension(Arrays.asList(assembler), fm);
+
+        Extension repoinitExtension = 
feature.getExtensions().getByName(Extension.EXTENSION_NAME_REPOINIT);
+        assertNotNull(repoinitExtension);
+
+        String expected =
+                "create service user user1 with path 
/home/users/system/cq:services/intermediate" + System.lineSeparator() +
+                "set principal ACL for user1" + System.lineSeparator() +
+                "allow jcr:read on home(user1)" + System.lineSeparator() +
+                "end" + System.lineSeparator();
+
+        String actual = repoinitExtension.getText();
+        assertEquals(expected, actual);
+
+        RepoInitParser repoInitParser = new RepoInitParserService();
+        List<Operation> operations = repoInitParser.parse(new 
StringReader(actual));
+        assertFalse(operations.isEmpty());
+    }
+}
\ No newline at end of file
diff --git 
a/src/test/java/org/apache/sling/feature/cpconverter/handlers/ParseResult.java 
b/src/test/java/org/apache/sling/feature/cpconverter/handlers/ParseResult.java
new file mode 100644
index 0000000..3952f3a
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/feature/cpconverter/handlers/ParseResult.java
@@ -0,0 +1,22 @@
+package org.apache.sling.feature.cpconverter.handlers;
+
+import org.apache.sling.feature.Extension;
+
+final class ParseResult {
+
+    private final Extension repoinitExtension;
+    private final String excludedAcls;
+
+    public ParseResult(Extension repoinitExtension, String excludedAcls) {
+        this.repoinitExtension = repoinitExtension;
+        this.excludedAcls = excludedAcls;
+    }
+
+    public Extension getRepoinitExtension() {
+        return repoinitExtension;
+    }
+
+    public String getExcludedAcls() {
+        return excludedAcls;
+    }
+}
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 e2d9889..d72adb6 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
@@ -16,22 +16,14 @@
  */
 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.sling.feature.ArtifactId;
 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;
-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;
@@ -41,9 +33,7 @@ import org.junit.Before;
 import org.junit.Test;
 
 import java.io.ByteArrayOutputStream;
-import java.io.File;
 import java.io.StringReader;
-import java.util.Arrays;
 import java.util.List;
 
 import static org.junit.Assert.assertEquals;
@@ -51,10 +41,8 @@ import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
-import static org.mockito.Mockito.when;
 
 public final class RepPolicyEntryHandlerTest {
 
@@ -244,7 +232,7 @@ public final class RepPolicyEntryHandlerTest {
                 "allow jcr:read,rep:userManagement on /home/groups/g" + 
System.lineSeparator() +
                 "end" + System.lineSeparator();
         assertEquals(expected, repoinitExtension.getText());
-        assertTrue(result.excludedAcls.isEmpty());
+        assertTrue(result.getExcludedAcls().isEmpty());
     }
 
     @Test
@@ -272,7 +260,7 @@ public final class RepPolicyEntryHandlerTest {
         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);
+        assertEquals(expectedExclusions, result.getExcludedAcls());
     }
 
     @Test(expected = IllegalStateException.class)
@@ -326,23 +314,4 @@ public final class RepPolicyEntryHandlerTest {
         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) {
-            this.repoinitExtension = repoinitExtension;
-            this.excludedAcls = excludedAcls;
-        }
-
-        public Extension getRepoinitExtension() {
-            return repoinitExtension;
-        }
-
-        public String getExcludedAcls() {
-            return excludedAcls;
-        }
-    }
 }
diff --git 
a/src/test/java/org/apache/sling/feature/cpconverter/handlers/RepPrincipalPolicyEntryHandlerTest.java
 
b/src/test/java/org/apache/sling/feature/cpconverter/handlers/RepPrincipalPolicyEntryHandlerTest.java
new file mode 100644
index 0000000..6fba859
--- /dev/null
+++ 
b/src/test/java/org/apache/sling/feature/cpconverter/handlers/RepPrincipalPolicyEntryHandlerTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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.Extension;
+import org.apache.sling.feature.ExtensionType;
+import org.apache.sling.feature.cpconverter.accesscontrol.AclManager;
+import org.apache.sling.feature.cpconverter.accesscontrol.DefaultAclManager;
+import org.apache.sling.feature.cpconverter.accesscontrol.SystemUser;
+import org.apache.sling.feature.cpconverter.shared.RepoPath;
+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;
+
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.StringReader;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+public final class RepPrincipalPolicyEntryHandlerTest {
+
+    private RepPrincipalPolicyEntryHandler handler;
+
+    @Before
+    public void setUp() {
+        handler = new RepPrincipalPolicyEntryHandler();
+    }
+
+    @After
+    public void tearDown() {
+        handler = null;
+    }
+
+    @Test
+    public void doesNotMatch() {
+        
assertFalse(handler.matches("/this/is/a/path/not/pointing/to/a/valid/_rep_principalPolicy.xml"));
+        
assertFalse(handler.matches("/home/users/system/asd-share-commons/asd-index-definition-reader/_rep_principalPolicy.xml"));
+        
assertFalse(handler.matches("/jcr_root/home/users/system/services/feature/random1/_rep_policy.xml"));
+    }
+
+    @Test
+    public void matches() {
+        
assertTrue(handler.matches("/jcr_root/home/users/system/services/random1/_rep_principalPolicy.xml"));
+    }
+
+    @Test
+    public void parseSimplePolicy() throws Exception {
+        Extension repoinitExtension = parseAndSetRepoinit("service1", 
"random1").getRepoinitExtension();
+        assertNotNull(repoinitExtension);
+        assertEquals(ExtensionType.TEXT, repoinitExtension.getType());
+
+        String expected =
+                "create service user service1 with path 
/home/users/system/services" + System.lineSeparator() +
+                "set principal ACL for service1\n" +
+                "allow jcr:read,jcr:readAccessControl on /asd/public\n" +
+                "end\n";
+
+        String actual = repoinitExtension.getText();
+        assertEquals(expected, actual);
+
+        RepoInitParser repoInitParser = new RepoInitParserService();
+        List<Operation> operations = repoInitParser.parse(new 
StringReader(actual));
+        assertFalse(operations.isEmpty());
+    }
+
+    @Test
+    public void parseMvRestrictions() throws Exception {
+        Extension repoinitExtension = parseAndSetRepoinit("service2", 
"random2").getRepoinitExtension();
+        assertNotNull(repoinitExtension);
+        assertEquals(ExtensionType.TEXT, repoinitExtension.getType());
+
+        String expected =
+                "create service user service2 with path 
/home/users/system/services" + System.lineSeparator() +
+                        "set principal ACL for service2\n" +
+                        "allow jcr:read on /asd/public 
restriction(rep:ntNames,nt:folder,sling:Folder)\n" +
+                        "end\n";
+
+        String actual = repoinitExtension.getText();
+        assertEquals(expected, actual);
+
+        RepoInitParser repoInitParser = new RepoInitParserService();
+        List<Operation> operations = repoInitParser.parse(new 
StringReader(actual));
+        assertFalse(operations.isEmpty());
+    }
+
+    @Test
+    public void parseUserHome() throws Exception {
+        Extension repoinitExtension = parseAndSetRepoinit("service3", 
"random3").getRepoinitExtension();
+        assertNotNull(repoinitExtension);
+        assertEquals(ExtensionType.TEXT, repoinitExtension.getType());
+
+        String expected =
+                "create service user service3 with path 
/home/users/system/services" + System.lineSeparator() +
+                        "set principal ACL for service3\n" +
+                        "allow jcr:all on home(service3)/subtree\n" +
+                        "end\n";
+
+        String actual = repoinitExtension.getText();
+        assertEquals(expected, actual);
+
+        RepoInitParser repoInitParser = new RepoInitParserService();
+        List<Operation> operations = repoInitParser.parse(new 
StringReader(actual));
+        assertFalse(operations.isEmpty());
+    }
+
+    @Test
+    public void parseOtherUserHomeSubtree() throws Exception {
+        Extension repoinitExtension = parseAndSetRepoinit("service4", 
"random4").getRepoinitExtension();
+        assertNotNull(repoinitExtension);
+        assertEquals(ExtensionType.TEXT, repoinitExtension.getType());
+
+        String expected =
+                "create service user service4 with path 
/home/users/system/services" + System.lineSeparator() +
+                "set principal ACL for service4\n" +
+                "allow jcr:read,rep:userManagement on home(service3)\n" +
+                "end\n";
+
+        String actual = repoinitExtension.getText();
+        assertEquals(expected, actual);
+
+        RepoInitParser repoInitParser = new RepoInitParserService();
+        List<Operation> operations = repoInitParser.parse(new 
StringReader(actual));
+        assertFalse(operations.isEmpty());
+    }
+
+    private ParseResult parseAndSetRepoinit(@NotNull String systemUsersName, 
@NotNull String nodeName) throws Exception {
+        RepoPath repoPath = new 
RepoPath("/home/users/system/services/"+nodeName);
+        return parseAndSetRepoinit(new SystemUser(systemUsersName, repoPath, 
new RepoPath("/home/users/system/services")));
+    }
+
+    private ParseResult parseAndSetRepoinit(SystemUser systemUser) throws 
Exception {
+        String path = "/jcr_root"+systemUser.getPath().toString() + 
"/_rep_principalPolicy.xml";
+        AclManager aclManager = new DefaultAclManager();
+        aclManager.addSystemUser(systemUser);
+
+        InputStream is = getClass().getResourceAsStream(path.substring(1));
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        return new ParseResult(TestUtils.createRepoInitExtension(handler, 
aclManager, path, is, baos), new String(baos.toByteArray()));
+    }
+
+}
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random1/_rep_principalPolicy.xml
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random1/_rep_principalPolicy.xml
new file mode 100644
index 0000000..e55c57f
--- /dev/null
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random1/_rep_principalPolicy.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:PrincipalPolicy"
+          rep:principalName="service1">
+    <entry0
+            jcr:primaryType="rep:PrincipalEntry"
+            rep:privileges="{Name}[jcr:read,jcr:readAccessControl]"
+            rep:effectivePath="/asd/public">
+    </entry0>
+</jcr:root>
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random2/_rep_principalPolicy.xml
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random2/_rep_principalPolicy.xml
new file mode 100644
index 0000000..38f5335
--- /dev/null
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random2/_rep_principalPolicy.xml
@@ -0,0 +1,29 @@
+<?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:PrincipalPolicy"
+          rep:principalName="service2">
+    <entry0
+            jcr:primaryType="rep:PrincipalEntry"
+            rep:privileges="{Name}[jcr:read]"
+            rep:effectivePath="/asd/public">
+        <rep:restrictions
+                jcr:primaryType="rep:Restrictions"
+                rep:ntNames="{Name}[nt:folder,sling:Folder]"/>
+    </entry0>
+</jcr:root>
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random3/_rep_principalPolicy.xml
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random3/_rep_principalPolicy.xml
new file mode 100644
index 0000000..f5048c0
--- /dev/null
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random3/_rep_principalPolicy.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:PrincipalPolicy"
+          rep:principalName="service3">
+    <entry0
+            jcr:primaryType="rep:PrincipalEntry"
+            rep:privileges="{Name}[jcr:all]"
+            rep:effectivePath="/home/users/system/services/random3/subtree">
+    </entry0>
+</jcr:root>
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random4/_rep_principalPolicy.xml
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random4/_rep_principalPolicy.xml
new file mode 100644
index 0000000..eff8224
--- /dev/null
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/home/users/system/services/random4/_rep_principalPolicy.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:PrincipalPolicy"
+          rep:principalName="service4">
+    <entry0
+            jcr:primaryType="rep:PrincipalEntry"
+            rep:privileges="{Name}[jcr:read,rep:userManagement]"
+            rep:effectivePath="/home/users/system/services/random3">
+    </entry0>
+</jcr:root>

Reply via email to