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

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

commit 7cc7d82a49f227492c2b437ec0bb82bb16ca70a9
Author: angela <[email protected]>
AuthorDate: Tue Jan 19 15:27:43 2021 +0100

    SLING-10070 : Option to enforce principal-based authorization (wip)
---
 .../cpconverter/accesscontrol/AclManager.java      |  2 +
 .../accesscontrol/DefaultAclManager.java           | 78 ++++++++++++-------
 .../feature/cpconverter/accesscontrol/Mapping.java | 90 ++++++++++++++++++++++
 .../AbstractConfigurationEntryHandler.java         | 29 ++++++-
 .../handlers/ConfigurationEntryHandlerTest.java    | 20 +++--
 .../JsonConfigurationEntryHandlerTest.java         | 34 ++++++++
 .../feature/cpconverter/handlers/TestUtils.java    |  3 +
 ...ceusermapping.impl.ServiceUserMapperImpl.config |  2 +-
 ...ceusermapping.impl.ServiceUserMapperImpl.config |  2 +-
 ...rviceusermapping.impl.ServiceUserMapperImpl.cfg |  2 +-
 ...usermapping.impl.ServiceUserMapperImpl.cfg.json |  5 +-
 ...ceusermapping.impl.ServiceUserMapperImpl.config |  2 +-
 ...ermapping.impl.ServiceUserMapperImpl.config.xml |  2 +-
 ...sermapping.impl.ServiceUserMapperImpl.typed.xml |  2 +-
 ...rviceusermapping.impl.ServiceUserMapperImpl.xml |  2 +-
 ...eusermapping.impl.ServiceUserMapperImpl.xml.cfg |  2 +-
 16 files changed, 232 insertions(+), 45 deletions(-)

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 8ca506d..95f2f75 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
@@ -34,6 +34,8 @@ public interface AclManager {
 
     boolean addSystemUser(@NotNull SystemUser systemUser);
 
+    void addMapping(@NotNull Mapping mapping);
+
     boolean addAcl(@NotNull String systemUser, @NotNull AccessControlEntry 
acl);
 
     void addRepoinitExtension(@NotNull List<VaultPackageAssembler> 
packageAssemblers, @NotNull FeaturesManager featureManager);
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 aff08fc..6d6907c 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
@@ -32,6 +32,8 @@ import javax.jcr.NamespaceException;
 import java.io.File;
 import java.io.FileInputStream;
 import java.util.Collection;
+import java.util.HashSet;
+import java.util.Optional;
 import java.util.Formatter;
 import java.util.HashMap;
 import java.util.LinkedHashMap;
@@ -41,7 +43,6 @@ 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;
@@ -57,6 +58,7 @@ public class DefaultAclManager implements AclManager {
     private final Set<SystemUser> systemUsers = new LinkedHashSet<>();
     private final Set<Group> groups = new LinkedHashSet<>();
     private final Set<User> users = new LinkedHashSet<>();
+    private final Set<Mapping> mappings = new HashSet<>();
 
     private final Map<String, List<AccessControlEntry>> acls = new HashMap<>();
 
@@ -88,6 +90,11 @@ public class DefaultAclManager implements AclManager {
     }
 
     @Override
+    public void addMapping(@NotNull Mapping mapping) {
+        mappings.add(mapping);
+    }
+
+    @Override
     public boolean addAcl(@NotNull String systemUser, @NotNull 
AccessControlEntry acl) {
         if (getSystemUser(systemUser).isPresent()) {
             acls.computeIfAbsent(systemUser, k -> new LinkedList<>()).add(acl);
@@ -128,7 +135,7 @@ public class DefaultAclManager implements AclManager {
     private void addUsersAndGroups(@NotNull Formatter formatter) {
         for (SystemUser systemUser : systemUsers) {
             // make sure all system users are created first
-            formatter.format("create service user %s with path %s%n", 
systemUser.getId(), 
calculateIntermediatePath(systemUser.getIntermediatePath()));
+            formatter.format("create service user %s with path %s%n", 
systemUser.getId(), calculateIntermediatePath(systemUser));
             if (aclIsBelow(systemUser.getPath())) {
                 throw new IllegalStateException("Detected policy on subpath of 
system-user: " + systemUser);
             }
@@ -144,8 +151,9 @@ public class DefaultAclManager implements AclManager {
     }
 
     @NotNull
-    private String calculateIntermediatePath(@NotNull RepoPath 
intermediatePath) {
-        if (enforcePrincipalBased && supportedPrincipalBasedPath != null && 
!intermediatePath.startsWith(supportedPrincipalBasedPath)) {
+    private String calculateIntermediatePath(@NotNull SystemUser systemUser) {
+        RepoPath intermediatePath = systemUser.getIntermediatePath();
+        if (enforcePrincipalBased(systemUser) && supportedPrincipalBasedPath 
!= null && !intermediatePath.startsWith(supportedPrincipalBasedPath)) {
             RepoPath parent = intermediatePath.getParent();
             while (parent != null) {
                 if (supportedPrincipalBasedPath.startsWith(parent)) {
@@ -161,27 +169,30 @@ public class DefaultAclManager implements AclManager {
     }
 
     private void addPaths(@NotNull Formatter formatter, @NotNull 
List<VaultPackageAssembler> packageAssemblers) {
-        if (!enforcePrincipalBased) {
-            Set<RepoPath> paths = acls.entrySet().stream()
-                    .filter(entry -> getSystemUser(entry.getKey()).isPresent())
-                    .map(Entry::getValue)
-                    .flatMap(Collection::stream)
-                    // paths only should/need to be create with resource-based 
access control
-                    .filter(((Predicate<AccessControlEntry>) 
AccessControlEntry::isPrincipalBased).negate())
-                    .map(AccessControlEntry::getRepositoryPath)
-                    .collect(Collectors.toSet());
-
-            paths.stream()
-                    .filter(path -> paths.stream().noneMatch(other -> 
!other.equals(path) && other.startsWith(path)))
-                    
.filter(((Predicate<RepoPath>)RepoPath::isRepositoryPath).negate())
-                    .filter(path -> Stream.of(systemUsers, users, 
groups).flatMap(Collection::stream)
-                            .noneMatch(user -> 
user.getPath().startsWith(path)))
-                    .map(path -> computePathWithTypes(path, packageAssemblers))
-                    .filter(Objects::nonNull)
-                    .forEach(
-                            path -> formatter.format("create path %s%n", path)
-                    );
-        }
+        Set<RepoPath> paths = acls.entrySet().stream()
+                // filter paths if service user does not exist or will have 
principal-based ac setup enforced
+                .filter(entry -> {
+                    Optional<SystemUser> su = getSystemUser(entry.getKey());
+                    return su.isPresent() && !enforcePrincipalBased(su.get());
+                })
+                .filter(entry -> getSystemUser(entry.getKey()).isPresent())
+                .map(Entry::getValue)
+                .flatMap(Collection::stream)
+                // paths only should/need to be create with resource-based 
access control
+                .filter(((Predicate<AccessControlEntry>) 
AccessControlEntry::isPrincipalBased).negate())
+                .map(AccessControlEntry::getRepositoryPath)
+                .collect(Collectors.toSet());
+
+        paths.stream()
+                .filter(path -> paths.stream().noneMatch(other -> 
!other.equals(path) && other.startsWith(path)))
+                
.filter(((Predicate<RepoPath>)RepoPath::isRepositoryPath).negate())
+                .filter(path -> Stream.of(systemUsers, users, 
groups).flatMap(Collection::stream)
+                        .noneMatch(user -> user.getPath().startsWith(path)))
+                .map(path -> computePathWithTypes(path, packageAssemblers))
+                .filter(Objects::nonNull)
+                .forEach(
+                        path -> formatter.format("create path %s%n", path)
+                );
     }
 
     private boolean aclStartsWith(@NotNull RepoPath path) {
@@ -200,7 +211,7 @@ public class DefaultAclManager implements AclManager {
 
         authorizations.forEach(entry -> {
             String path = getRepoInitPath(entry.getRepositoryPath(), 
systemUser);
-            if (enforcePrincipalBased || entry.isPrincipalBased()) {
+            if (entry.isPrincipalBased() || enforcePrincipalBased(systemUser)) 
{
                 principalEntries.put(entry, path);
             } else {
                 resourceEntries.put(entry, path);
@@ -219,6 +230,21 @@ public class DefaultAclManager implements AclManager {
         }
     }
 
+    private boolean enforcePrincipalBased(@NotNull SystemUser systemUser) {
+        if (!enforcePrincipalBased) {
+            return false;
+        } else {
+            // FIXME: avoid iterating over mappings multiple times
+            String id = systemUser.getId();
+            for (Mapping mapping : mappings) {
+                if (mapping.mapsUser(id)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+    }
+
     private void writeEntry(@NotNull AccessControlEntry entry, @NotNull String 
path, @NotNull Formatter formatter) {
         formatter.format("%s %s on %s",
                 entry.getOperation(),
diff --git 
a/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/Mapping.java 
b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/Mapping.java
new file mode 100644
index 0000000..f815c1a
--- /dev/null
+++ 
b/src/main/java/org/apache/sling/feature/cpconverter/accesscontrol/Mapping.java
@@ -0,0 +1,90 @@
+/*
+ * 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 java.util.LinkedHashSet;
+import java.util.Set;
+
+public class Mapping {
+
+    private final String serviceName;
+
+    private final String subServiceName;
+
+    private final String userName;
+
+    private final Set<String> principalNames;
+
+    /**
+     * Copied from 
https://github.com/apache/sling-org-apache-sling-serviceusermapper/blob/master/src/main/java/org/apache/sling/serviceusermapping/Mapping.java
+     */
+    public Mapping(final String spec) {
+
+        final int colon = spec.indexOf(':');
+        final int equals = spec.indexOf('=');
+
+        if (colon == 0 || equals <= 0) {
+            throw new IllegalArgumentException("serviceName is required");
+        } else if (equals == spec.length() - 1) {
+            throw new IllegalArgumentException("userName or principalNames is 
required");
+        } else if (colon + 1 == equals) {
+            throw new IllegalArgumentException("serviceInfo must not be 
empty");
+        }
+
+        if (colon < 0 || colon > equals) {
+            this.serviceName = spec.substring(0, equals);
+            this.subServiceName = null;
+        } else {
+            this.serviceName = spec.substring(0, colon);
+            this.subServiceName = spec.substring(colon + 1, equals);
+        }
+
+        String s = spec.substring(equals + 1);
+        if (s.charAt(0) == '[' && s.charAt(s.length()-1) == ']') {
+            this.userName = null;
+            this.principalNames = extractPrincipalNames(s);
+        } else {
+            this.userName = s;
+            this.principalNames = null;
+        }
+    }
+
+    /**
+     * Copied from 
https://github.com/apache/sling-org-apache-sling-serviceusermapper/blob/master/src/main/java/org/apache/sling/serviceusermapping/Mapping.java
+     */
+    private static Set<String> extractPrincipalNames(String s) {
+        String[] sArr = s.substring(1, s.length() - 1).split(",");
+        Set<String> set = new LinkedHashSet<>();
+        for (String name : sArr) {
+            String n = name.trim();
+            if (!n.isEmpty()) {
+                set.add(n);
+            }
+        }
+        return set;
+    }
+
+    public boolean mapsUser(@NotNull String userId) {
+        return userId.equals(this.userName);
+    }
+
+    public boolean mapsPrincipal(@NotNull String principalName) {
+        return this.principalNames != null && 
principalNames.contains(principalName);
+    }
+}
\ 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 8be1241..1fbc546 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
@@ -24,6 +24,9 @@ import java.util.regex.Matcher;
 import org.apache.jackrabbit.vault.fs.io.Archive;
 import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
 import 
org.apache.sling.feature.cpconverter.ContentPackage2FeatureModelConverter;
+import org.apache.sling.feature.cpconverter.accesscontrol.AclManager;
+import org.apache.sling.feature.cpconverter.accesscontrol.Mapping;
+import org.apache.sling.feature.cpconverter.features.FeaturesManager;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.osgi.util.converter.Converters;
@@ -34,6 +37,8 @@ abstract class AbstractConfigurationEntryHandler extends 
AbstractRegexEntryHandl
 
     private static final String REPOINIT_PID = 
"org.apache.sling.jcr.repoinit.impl.RepositoryInitializer";
 
+    private static final String SERVICE_USER_MAPPING_PID = 
"org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl";
+
     public AbstractConfigurationEntryHandler(@NotNull String extension) {
         
super("/jcr_root/(?:apps|libs)/.+/config(\\.(?<runmode>[^/]+))?/(?<pid>.*)\\." 
+ extension);
     }
@@ -80,22 +85,38 @@ abstract class AbstractConfigurationEntryHandler extends 
AbstractRegexEntryHandl
             }
             // there is a specified RunMode
             runMode = matcher.group("runmode");
-            
+
+            FeaturesManager featuresManager = 
Objects.requireNonNull(converter.getFeaturesManager());
             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() ) {
-                            
Objects.requireNonNull(converter.getFeaturesManager()).addOrAppendRepoInitExtension(text,
 runMode);
+                            featuresManager.addOrAppendRepoInitExtension(text, 
runMode);
                         }
                     }
                 }
                 checkReferences(configurationProperties, pid);
             } else if ( REPOINIT_PID.equals(pid) ) {
                 checkReferences(configurationProperties, pid);
-
+            } else if (pid.startsWith(SERVICE_USER_MAPPING_PID)) {
+                Object mappings = configurationProperties.get("user.mapping");
+                if (mappings != null) {
+                    String[] usermappings;
+                    if (mappings instanceof String[]) {
+                        usermappings = (String[]) mappings;
+                    } else {
+                        // FIXME
+                        throw new IllegalStateException(path + " => '" + 
mappings.toString() + "'");
+                    }
+                    AclManager aclManager = 
Objects.requireNonNull(converter.getAclManager());
+                    for (String usermapping : usermappings) {
+                        aclManager.addMapping(new Mapping(usermapping));
+                    }
+                }
+                featuresManager.addConfiguration(runMode, id, 
configurationProperties);
             } else {
-                
Objects.requireNonNull(converter.getFeaturesManager()).addConfiguration(runMode,
 id, configurationProperties);
+                featuresManager.addConfiguration(runMode, id, 
configurationProperties);
             }
         } else {
             throw new IllegalStateException("Something went terribly wrong: 
pattern '"
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 b5ddbd4..f354de6 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
@@ -24,12 +24,15 @@ 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;
 
 import java.io.StringWriter;
 import java.io.Writer;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Dictionary;
 
 import org.apache.jackrabbit.vault.fs.io.Archive;
 import org.apache.jackrabbit.vault.fs.io.Archive.Entry;
@@ -39,6 +42,8 @@ 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.Mapping;
 import org.apache.sling.feature.cpconverter.features.DefaultFeaturesManager;
 import org.apache.sling.feature.cpconverter.features.FeaturesManager;
 import org.apache.sling.feature.io.json.ConfigurationJSONWriter;
@@ -71,9 +76,10 @@ public class ConfigurationEntryHandlerTest {
         "    \"test.dateproperty\":1604743842669,\n" + 
         "    \"test.booleanproperty\":true,\n" + 
         "    \"user.mapping\":[\n" + 
-        "      \"com.adobe.acs.acs-aem-samples-bundle=admin\",\n" + 
-        "      
\"com.adobe.acs.acs-aem-samples-bundle:sample-service=oauthservice\"\n" + 
-        "    ]\n" + 
+        "      \"org.apache.sling.testbundle:sub-service-1=service1\",\n" +
+        "      
\"org.apache.sling.testbundle:sub-service-2=[service1,service2]\",\n" +
+        "      
\"org.apache.sling.testbundle=[service1,external-service-user]\"\n" +
+        "    ]\n" +
         "  }\n" + 
         "}";
     
@@ -122,6 +128,8 @@ public class ConfigurationEntryHandlerTest {
         when(featuresManager.getRunMode(anyString())).thenReturn(feature);
         ContentPackage2FeatureModelConverter converter = 
mock(ContentPackage2FeatureModelConverter.class);
         when(converter.getFeaturesManager()).thenReturn(featuresManager);
+        AclManager aclManager = mock(AclManager.class);
+        when(converter.getAclManager()).thenReturn(aclManager);
 
         configurationEntryHandler.handle(resourceConfiguration, archive, 
entry, converter);
 
@@ -138,10 +146,12 @@ public class ConfigurationEntryHandlerTest {
 
             assertTrue(configuration.getPid(), 
configuration.getPid().startsWith(EXPECTED_PID));
 
+            Dictionary<String,Object> props = configuration.getProperties();
             if (configuration.getPid().contains(".empty")) {
-                assertTrue(configuration.getProperties().isEmpty());
+                assertTrue(props.isEmpty());
             } else {
-                assertEquals("Unmatching size: " + 
configuration.getProperties().size(), expectedConfigurationsEntrySize, 
configuration.getProperties().size());
+                assertEquals("Unmatching size: " + props.size(), 
expectedConfigurationsEntrySize, configuration.getProperties().size());
+                verify(aclManager, times(3)).addMapping(any(Mapping.class));
             }
             // type & value check for typed configuration
             if (this.resourceConfiguration.equals(TYPED_TESTCONFIG_PATH)) {
diff --git 
a/src/test/java/org/apache/sling/feature/cpconverter/handlers/JsonConfigurationEntryHandlerTest.java
 
b/src/test/java/org/apache/sling/feature/cpconverter/handlers/JsonConfigurationEntryHandlerTest.java
index 9711ba8..67d2ec9 100644
--- 
a/src/test/java/org/apache/sling/feature/cpconverter/handlers/JsonConfigurationEntryHandlerTest.java
+++ 
b/src/test/java/org/apache/sling/feature/cpconverter/handlers/JsonConfigurationEntryHandlerTest.java
@@ -16,14 +16,24 @@
  */
 package org.apache.sling.feature.cpconverter.handlers;
 
+import static org.mockito.ArgumentMatchers.any;
 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;
 
 import java.io.IOException;
 
 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.Feature;
 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.DefaultFeaturesManager;
+import org.apache.sling.feature.cpconverter.features.FeaturesManager;
 import org.junit.Test;
 
 public class JsonConfigurationEntryHandlerTest {
@@ -43,4 +53,28 @@ public class JsonConfigurationEntryHandlerTest {
         new JsonConfigurationEntryHandler().handle(resourceConfiguration, 
archive, entry, converter);
     }
 
+    @Test
+    public void validConfigurationThrowsException() throws Exception {
+        String resourceConfiguration = 
"/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg.json";
+
+        Archive archive = mock(Archive.class);
+        Entry entry = mock(Entry.class);
+
+        
when(entry.getName()).thenReturn(resourceConfiguration.substring(resourceConfiguration.lastIndexOf('/')
 + 1));
+        
when(archive.openInputStream(entry)).thenReturn(getClass().getResourceAsStream(resourceConfiguration.substring(1)));
+
+        AclManager aclManager = mock(AclManager.class);
+        Feature feature = new Feature(new ArtifactId("org.apache.sling", 
"org.apache.sling.cp2fm", "0.0.1", null, null));
+        FeaturesManager featuresManager = spy(DefaultFeaturesManager.class);
+        when(featuresManager.getTargetFeature()).thenReturn(feature);
+
+        ContentPackage2FeatureModelConverter converter = 
mock(ContentPackage2FeatureModelConverter.class);
+        when(converter.getAclManager()).thenReturn(aclManager);
+        when(converter.getFeaturesManager()).thenReturn(featuresManager);
+
+        new JsonConfigurationEntryHandler().handle(resourceConfiguration, 
archive, entry, converter);
+
+        verify(aclManager, times(3)).addMapping(any(Mapping.class));
+    }
+
 }
diff --git 
a/src/test/java/org/apache/sling/feature/cpconverter/handlers/TestUtils.java 
b/src/test/java/org/apache/sling/feature/cpconverter/handlers/TestUtils.java
index a950260..737a777 100644
--- a/src/test/java/org/apache/sling/feature/cpconverter/handlers/TestUtils.java
+++ b/src/test/java/org/apache/sling/feature/cpconverter/handlers/TestUtils.java
@@ -31,8 +31,10 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.io.File;
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.security.acl.Acl;
 import java.util.Collections;
 
 import static org.mockito.ArgumentMatchers.anyString;
@@ -49,6 +51,7 @@ class TestUtils {
     static Extension createRepoInitExtension(@NotNull EntryHandler handler, 
@NotNull AclManager aclManager, @NotNull String path, @NotNull InputStream is) 
throws Exception {
         return createRepoInitExtension(handler, aclManager, path, is, null);
     }
+
     static Extension createRepoInitExtension(@NotNull EntryHandler handler, 
@NotNull AclManager aclManager, @NotNull String path, @NotNull InputStream is, 
@Nullable OutputStream out) throws Exception {
         Archive archive = mock(Archive.class);
         Archive.Entry entry = mock(Archive.Entry.class);
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.author/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.author/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
index 4c50ea3..d8884c9 100644
--- 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.author/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.author/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
@@ -14,4 +14,4 @@
 # the License.
 
 user.default="admin"
-user.mapping=["com.adobe.acs.acs-aem-samples-bundle\=admin","com.adobe.acs.acs-aem-samples-bundle:sample-service\=oauthservice"]
+user.mapping=["org.apache.sling.testbundle:sub-service-1\=service1","org.apache.sling.testbundle:sub-service-2\=[service1,service2]","org.apache.sling.testbundle\=[service1,external-service-user]"]
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
index 4c50ea3..fc60138 100644
--- 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config.publish/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
@@ -14,4 +14,4 @@
 # the License.
 
 user.default="admin"
-user.mapping=["com.adobe.acs.acs-aem-samples-bundle\=admin","com.adobe.acs.acs-aem-samples-bundle:sample-service\=oauthservice"]
+user.mapping=["org.apache.sling.testbundle:sub-service-1\=service1","org.apache.sling.testbundle:sub-service-2\=[service1,service2]","org.apache.sling.testbundle\=org.apache.sling.testbundle\=[service1,external-service-user]"]
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg
index bf91183..1aac913 100644
--- 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg
@@ -14,4 +14,4 @@
 # the License.
 
 user.default=admin
-user.mapping=[com.adobe.acs.acs-aem-samples-bundle=admin,com.adobe.acs.acs-aem-samples-bundle:sample-service=oauthservice]
+user.mapping=[org.apache.sling.testbundle:sub-service-1=service-1,org.apache.sling.testbundle:sub-service-2=[service1,service2],org.apache.sling.testbundle=[service1,external-service-user]]
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg.json
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg.json
index 98e506c..3b80428 100644
--- 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg.json
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.cfg.json
@@ -1,7 +1,8 @@
 {
     "user.default":"admin",
     "user.mapping": [
-        "com.adobe.acs.acs-aem-samples-bundle=admin",
-        "com.adobe.acs.acs-aem-samples-bundle:sample-service=oauthservice"
+        "org.apache.sling.testbundle:sub-service-1=service1",
+        "org.apache.sling.testbundle:sub-service-2=[service1,service2]",
+        "org.apache.sling.testbundle=[service1,external-service-user]"
     ]
 }
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
index 4c50ea3..d8884c9 100644
--- 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config
@@ -14,4 +14,4 @@
 # the License.
 
 user.default="admin"
-user.mapping=["com.adobe.acs.acs-aem-samples-bundle\=admin","com.adobe.acs.acs-aem-samples-bundle:sample-service\=oauthservice"]
+user.mapping=["org.apache.sling.testbundle:sub-service-1\=service1","org.apache.sling.testbundle:sub-service-2\=[service1,service2]","org.apache.sling.testbundle\=[service1,external-service-user]"]
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config.xml
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config.xml
index f23afc9..7b8c6ca 100644
--- 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config.xml
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.config.xml
@@ -18,4 +18,4 @@
 <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"; 
xmlns:jcr="http://www.jcp.org/jcr/1.0";
     jcr:primaryType="sling:OsgiConfig"
     user.default="admin"
-    
user.mapping="[com.adobe.acs.acs-aem-samples-bundle=admin,com.adobe.acs.acs-aem-samples-bundle:sample-service=oauthservice]"/>
+    
user.mapping="[org.apache.sling.testbundle:sub-service-1=service1,org.apache.sling.testbundle:sub-service-2=\[service1\,service2\],org.apache.sling.testbundle=\[service1\,external-service-user\]]"/>
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.typed.xml
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.typed.xml
index 91ed2cf..0f3e3c8 100644
--- 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.typed.xml
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.typed.xml
@@ -22,4 +22,4 @@
     test.doubleproperty="{Double}1.23"
     test.dateproperty="{Date}2020-11-07T10:10:42.669"
     test.booleanproperty="{Boolean}true"
-    
user.mapping="[com.adobe.acs.acs-aem-samples-bundle=admin,com.adobe.acs.acs-aem-samples-bundle:sample-service=oauthservice]"/>
+    
user.mapping="[org.apache.sling.testbundle:sub-service-1=service1,org.apache.sling.testbundle:sub-service-2=\[service1\,service2\],org.apache.sling.testbundle=\[service1\,external-service-user\]]"/>
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.xml
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.xml
index f23afc9..7b8c6ca 100644
--- 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.xml
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.xml
@@ -18,4 +18,4 @@
 <jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"; 
xmlns:jcr="http://www.jcp.org/jcr/1.0";
     jcr:primaryType="sling:OsgiConfig"
     user.default="admin"
-    
user.mapping="[com.adobe.acs.acs-aem-samples-bundle=admin,com.adobe.acs.acs-aem-samples-bundle:sample-service=oauthservice]"/>
+    
user.mapping="[org.apache.sling.testbundle:sub-service-1=service1,org.apache.sling.testbundle:sub-service-2=\[service1\,service2\],org.apache.sling.testbundle=\[service1\,external-service-user\]]"/>
diff --git 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.xml.cfg
 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.xml.cfg
index 05ce515..0707188 100644
--- 
a/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.xml.cfg
+++ 
b/src/test/resources/org/apache/sling/feature/cpconverter/handlers/jcr_root/apps/asd/config/org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.xml.cfg
@@ -18,5 +18,5 @@
 -->
 <properties>
   <entry key="user.default">admin</entry>
-  <entry 
key="user.mapping">[com.adobe.acs.acs-aem-samples-bundle=admin,com.adobe.acs.acs-aem-samples-bundle:sample-service=oauthservice]</entry>
+  <entry 
key="user.mapping">[org.apache.sling.testbundle:sub-service-1=service1,org.apache.sling.testbundle:sub-service-2=[service1,service2],org.apache.sling.testbundle=[service1,external-service-user]]</entry>
 </properties>

Reply via email to