You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by an...@apache.org on 2021/01/15 07:06:25 UTC
[sling-org-apache-sling-feature-cpconverter] 01/01: SLING-9692 :
Add support for principal-based access control entries
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 <an...@adobe.com>
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>