You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by kw...@apache.org on 2021/12/09 09:39:16 UTC
[sling-org-apache-sling-jcr-contentloader] 01/01: SLING-10983 never overwrite nodes on root level
This is an automated email from the ASF dual-hosted git repository.
kwin pushed a commit to branch feature/cleanup-overwrite
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-contentloader.git
commit 0a8c454d2e3be4818f6813696754589671a6c39c
Author: Konrad Windszus <kw...@apache.org>
AuthorDate: Thu Dec 9 10:39:05 2021 +0100
SLING-10983 never overwrite nodes on root level
SLING-10986 overwrite with a path directive should also overwite node at
path itself
---
.../internal/BundleContentLoader.java | 22 +++-
.../internal/BundleContentLoaderTest.java | 111 ++++++++++++++++++++-
.../SLING-INF2/apps/sling/validation/content.json | 3 +
3 files changed, 131 insertions(+), 5 deletions(-)
diff --git a/src/main/java/org/apache/sling/jcr/contentloader/internal/BundleContentLoader.java b/src/main/java/org/apache/sling/jcr/contentloader/internal/BundleContentLoader.java
index 8bbb26e..da76713 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/internal/BundleContentLoader.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/internal/BundleContentLoader.java
@@ -260,6 +260,10 @@ public class BundleContentLoader extends BaseImportLoader {
continue;
}
+ if (pathEntry.isOverwrite() && (pathEntry.getTarget() == null || "/".equals(pathEntry.getTarget()))) {
+ log.error("Path {} tries to overwrite on the repository root level which is not allowed, only use overwrite with a dedicated path directive having any value but '/'", pathEntry.getPath());
+ continue;
+ }
if (!contentAlreadyLoaded || pathEntry.isOverwrite()) {
String workspace = pathEntry.getWorkspace();
final Session targetSession;
@@ -274,7 +278,7 @@ public class BundleContentLoader extends BaseImportLoader {
targetSession = defaultSession;
}
- final Node targetNode = getTargetNode(targetSession, pathEntry.getTarget());
+ final Node targetNode = getTargetNode(targetSession, pathEntry.getTarget(), pathEntry.isOverwrite());
if (targetNode != null) {
installFromPath(bundle, pathEntry.getPath(), pathEntry, targetNode,
@@ -635,7 +639,7 @@ public class BundleContentLoader extends BaseImportLoader {
return name;
}
- private Node getTargetNode(Session session, String path) throws RepositoryException {
+ private Node getTargetNode(Session session, String path, boolean overwrite) throws RepositoryException {
// not specified path directive
if (path == null) {
@@ -658,9 +662,19 @@ public class BundleContentLoader extends BaseImportLoader {
currentNode = currentNode.getNode(name);
}
return currentNode;
+ } else {
+ Item item = session.getItem(path);
+ if (!item.isNode()) {
+ log.warn("Cannot overwrite item at path {} as this is an existing property", path);
+ return null;
+ }
+ Node targetNode = session.getNode(path);
+ // overwrite target node itself?
+ if (overwrite) {
+ targetNode = createFolder(targetNode.getParent(), targetNode.getName(), true);
+ }
+ return targetNode;
}
- Item item = session.getItem(path);
- return (item.isNode()) ? (Node) item : null;
}
private void uninstallContent(final Session defaultSession, final Bundle bundle, final String[] uninstallPaths) {
diff --git a/src/test/java/org/apache/sling/jcr/contentloader/internal/BundleContentLoaderTest.java b/src/test/java/org/apache/sling/jcr/contentloader/internal/BundleContentLoaderTest.java
index 6f6303c..fc5bb3c 100644
--- a/src/test/java/org/apache/sling/jcr/contentloader/internal/BundleContentLoaderTest.java
+++ b/src/test/java/org/apache/sling/jcr/contentloader/internal/BundleContentLoaderTest.java
@@ -22,19 +22,42 @@ import static java.util.Collections.singletonMap;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.CoreMatchers.nullValue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
import java.lang.annotation.Annotation;
+import java.security.Principal;
+import javax.jcr.AccessDeniedException;
+import javax.jcr.NamespaceException;
+import javax.jcr.RepositoryException;
import javax.jcr.Session;
-
+import javax.jcr.Workspace;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.Privilege;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.JackrabbitWorkspace;
+import org.apache.jackrabbit.api.security.authorization.PrivilegeManager;
+import org.apache.jackrabbit.commons.JcrUtils;
+import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.jcr.contentloader.internal.readers.JsonReader;
import org.apache.sling.jcr.contentloader.internal.readers.XmlReader;
import org.apache.sling.jcr.contentloader.internal.readers.ZipReader;
+import org.apache.sling.jcr.resource.internal.helper.JcrResourceUtil;
import org.apache.sling.testing.mock.osgi.MockBundle;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.hamcrest.MatcherAssert;
+import org.hamcrest.Matchers;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
@@ -50,6 +73,7 @@ public class BundleContentLoaderTest {
private ContentReaderWhiteboard whiteboard;
+ private static final String CUSTOM_PRIVILEGE_NAME = "customPrivilege";
@Before
public void prepareContentLoader() throws Exception {
// prepare content readers
@@ -67,6 +91,91 @@ public class BundleContentLoaderTest {
}
+ private static Privilege getOrRegisterCustomPrivilege(Session session) throws AccessDeniedException, NamespaceException, RepositoryException {
+ // register custom privilege
+ Workspace wsp = session.getWorkspace();
+ if (!(wsp instanceof JackrabbitWorkspace)) {
+ throw new RepositoryException("Unable to register privileges. No JackrabbitWorkspace.");
+ }
+ PrivilegeManager mgr = ((JackrabbitWorkspace) wsp).getPrivilegeManager();
+ try {
+ return mgr.getPrivilege(CUSTOM_PRIVILEGE_NAME);
+ } catch (AccessControlException e) {
+ return mgr.registerPrivilege(CUSTOM_PRIVILEGE_NAME, false, new String[0]);
+ }
+ }
+
+ private AccessControlEntry[] createFolderNodeAndACL(String path) throws RepositoryException {
+ // use JCR API to add some node and acl
+ Session session = context.resourceResolver().adaptTo(Session.class);
+
+ Privilege customPrivilege = getOrRegisterCustomPrivilege(session);
+ Privilege[] customPrivilegeSingleItemArray = new Privilege[]{ customPrivilege };
+
+ JcrUtils.getOrCreateByPath(path, NodeType.NT_FOLDER, session);
+
+ AccessControlManager acMgr = session.getAccessControlManager();
+ AccessControlList acl = (AccessControlList)acMgr.getApplicablePolicies(path).nextAccessControlPolicy();
+ Principal everyone = EveryonePrincipal.getInstance();
+ assertTrue(acl.addAccessControlEntry(everyone, customPrivilegeSingleItemArray));
+ AccessControlEntry[] expectedAces = acl.getAccessControlEntries();
+ acMgr.setPolicy(path, acl);
+ session.save();
+ return expectedAces;
+ }
+
+ private void assertFolderNodeAndACL(String path, AccessControlEntry[] expectedAces) throws RepositoryException {
+ Session session = context.resourceResolver().adaptTo(Session.class);
+ session.refresh(false);
+ assertTrue(session.nodeExists(path));
+ assertEquals(JcrConstants.NT_FOLDER, session.getNode(path).getPrimaryNodeType().getName());
+ AccessControlManager acMgr = session.getAccessControlManager();
+ AccessControlList acl = (AccessControlList)acMgr.getPolicies(path)[0];
+ AccessControlEntry[] aces = acl.getAccessControlEntries();
+ MatcherAssert.assertThat(aces, Matchers.arrayContaining(expectedAces));
+ }
+
+ @Test
+ public void loadContentOverwriteWithoutPath() throws Exception {
+ AccessControlEntry[] expectedAces = createFolderNodeAndACL("/apps/child");
+
+ // import without path
+ BundleContentLoader contentLoader = new BundleContentLoader(bundleHelper, whiteboard, null);
+ Bundle mockBundle = newBundleWithInitialContent(context, "SLING-INF2;overwrite:=true");
+ contentLoader.registerBundle(context.resourceResolver().adaptTo(Session.class), mockBundle, false);
+ Resource imported = context.resourceResolver().getResource("/apps/sling/validation/content");
+ assertNull("Resource was unexpectedly imported", imported);
+ assertFolderNodeAndACL("/apps/child", expectedAces);
+ }
+
+ @Test
+ public void loadContentOverwriteWithRootPath() throws Exception {
+ AccessControlEntry[] expectedAces = createFolderNodeAndACL("/apps/child");
+
+ // import without path
+ BundleContentLoader contentLoader = new BundleContentLoader(bundleHelper, whiteboard, null);
+ Bundle mockBundle = newBundleWithInitialContent(context, "SLING-INF2;overwrite:=true;path:=/");
+ contentLoader.registerBundle(context.resourceResolver().adaptTo(Session.class), mockBundle, false);
+ Resource imported = context.resourceResolver().getResource("/apps/sling/validation/content");
+ assertNull("Resource was unexpectedly imported", imported);
+ assertFolderNodeAndACL("/apps/child", expectedAces);
+ }
+
+ @Test
+ public void loadContentOverwriteWith2ndLevelPath() throws Exception {
+ AccessControlEntry[] expectedAces = createFolderNodeAndACL("/apps/child");
+
+ // import without path
+ BundleContentLoader contentLoader = new BundleContentLoader(bundleHelper, whiteboard, null);
+ Bundle mockBundle = newBundleWithInitialContent(context, "SLING-INF2/apps;overwrite:=true;path:=/apps");
+ contentLoader.registerBundle(context.resourceResolver().adaptTo(Session.class), mockBundle, false);
+ Resource imported = context.resourceResolver().getResource("/apps/sling/validation/content");
+
+ assertThat("Resource was not imported", imported, notNullValue());
+ assertThat("sling:resourceType was not properly set", imported.getResourceType(), equalTo("sling:Folder"));
+ assertNull(context.resourceResolver().getResource("/apps/child"));
+ }
+
@Test
public void loadContentWithSpecificPath() throws Exception {
diff --git a/src/test/resources/SLING-INF2/apps/sling/validation/content.json b/src/test/resources/SLING-INF2/apps/sling/validation/content.json
new file mode 100644
index 0000000..681774d
--- /dev/null
+++ b/src/test/resources/SLING-INF2/apps/sling/validation/content.json
@@ -0,0 +1,3 @@
+{
+ "jcr:primaryType" : "sling:Folder"
+}
\ No newline at end of file