diff --git a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadOnlyNodeTypeManager.java b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadOnlyNodeTypeManager.java index 3fdd4802c2..fd5b35c375 100644 --- a/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadOnlyNodeTypeManager.java +++ b/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/ReadOnlyNodeTypeManager.java @@ -25,6 +25,7 @@ import static org.apache.jackrabbit.oak.commons.PathUtils.dropIndexFromName; import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.NODE_TYPES_PATH; import static org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants.REP_SUPERTYPES; +import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -50,13 +51,18 @@ import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.api.Type; +import org.apache.jackrabbit.oak.commons.LazyValue; import org.apache.jackrabbit.oak.namepath.NameMapper; import org.apache.jackrabbit.oak.namepath.NamePathMapper; import org.apache.jackrabbit.oak.namepath.impl.NamePathMapperImpl; +import org.apache.jackrabbit.oak.plugins.memory.PropertyStates; +import org.apache.jackrabbit.oak.plugins.tree.TreeUtil; import org.apache.jackrabbit.oak.spi.nodetype.DefinitionProvider; import org.apache.jackrabbit.oak.spi.nodetype.EffectiveNodeType; import org.apache.jackrabbit.oak.spi.nodetype.EffectiveNodeTypeProvider; import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -68,6 +74,12 @@ import org.jetbrains.annotations.Nullable; */ public abstract class ReadOnlyNodeTypeManager implements NodeTypeManager, EffectiveNodeTypeProvider, DefinitionProvider { + /** + * Use an zero length MVP to check read permission on jcr:mixinTypes (OAK-7652) + */ + private static final PropertyState EMPTY_MIXIN_TYPES = PropertyStates.createProperty( + JcrConstants.JCR_MIXINTYPES, Collections.emptyList(), Type.NAMES); + /** * Returns the internal name for the specified JCR name. * @@ -254,34 +266,63 @@ public abstract class ReadOnlyNodeTypeManager implements NodeTypeManager, Effect // shortcuts for common cases if (JcrConstants.NT_BASE.equals(oakNtName)) { return true; - } else if (JcrConstants.MIX_REFERENCEABLE.equals(oakNtName) - && !tree.hasProperty(JcrConstants.JCR_UUID)) { - return false; - } else if (JcrConstants.MIX_VERSIONABLE.equals(oakNtName) - && !tree.hasProperty(JcrConstants.JCR_ISCHECKEDOUT)) { - return false; } Tree types = getTypes(); + String primary = getPrimaryTypeName(tree); + if (primary != null && isa(types, primary, oakNtName)) { + return true; + } - PropertyState primary = tree.getProperty(JcrConstants.JCR_PRIMARYTYPE); - if (primary != null && primary.getType() == Type.NAME) { - String name = primary.getValue(Type.NAME); + for (String name : getMixinTypeNames(tree)) { if (isa(types, name, oakNtName)) { return true; } } - PropertyState mixins = tree.getProperty(JcrConstants.JCR_MIXINTYPES); - if (mixins != null && mixins.getType() == Type.NAMES) { - for (String name : mixins.getValue(Type.NAMES)) { - if (isa(types, name, oakNtName)) { - return true; - } + return false; + } + + @Nullable + public String getPrimaryTypeName(@NotNull Tree tree) { + LazyValue fallback = getReadOnlyTree(tree); + if (fallback == null) { + return TreeUtil.getPrimaryTypeName(tree); + } else { + return TreeUtil.getPrimaryTypeName(tree, fallback); + } + } + + @NotNull + public Iterable getMixinTypeNames(@NotNull Tree tree) { + if (tree.hasProperty(JcrConstants.JCR_MIXINTYPES) || canReadMixinTypes(tree)) { + return TreeUtil.getMixinTypeNames(tree); + } else { + LazyValue fallback = getReadOnlyTree(tree); + if (fallback == null) { + return TreeUtil.getMixinTypeNames(tree); + } else { + return TreeUtil.getMixinTypeNames(tree, fallback); } } + } - return false; + @Nullable + protected LazyValue getReadOnlyTree(@NotNull Tree tree) { + return null; + } + + @Nullable + protected PermissionProvider getPermissionProvider() { + return null; + } + + private boolean canReadMixinTypes(@NotNull Tree tree) { + PermissionProvider permissionProvider = getPermissionProvider(); + if (permissionProvider == null) { + return true; + } + return permissionProvider.isGranted(tree, EMPTY_MIXIN_TYPES, Permissions.READ_PROPERTY); } @Override @@ -302,7 +343,7 @@ public abstract class ReadOnlyNodeTypeManager implements NodeTypeManager, Effect return false; } - private static boolean isa(Tree types, String typeName, String superName) { + private static boolean isa(@NotNull Tree types, @NotNull String typeName, @NotNull String superName) { if (typeName.equals(superName)) { return true; } diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java index 78918b2a18..7b0e5d2b02 100644 --- a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java +++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/NodeImpl.java @@ -59,7 +59,6 @@ import javax.jcr.lock.LockManager; import javax.jcr.nodetype.ConstraintViolationException; import javax.jcr.nodetype.NodeDefinition; import javax.jcr.nodetype.NodeType; -import javax.jcr.nodetype.NodeTypeManager; import javax.jcr.version.OnParentVersionAction; import javax.jcr.version.Version; import javax.jcr.version.VersionException; @@ -79,7 +78,6 @@ import org.apache.jackrabbit.oak.api.PropertyState; import org.apache.jackrabbit.oak.api.Tree; import org.apache.jackrabbit.oak.api.Tree.Status; import org.apache.jackrabbit.oak.api.Type; -import org.apache.jackrabbit.oak.commons.LazyValue; import org.apache.jackrabbit.oak.commons.PathUtils; import org.apache.jackrabbit.oak.jcr.delegate.NodeDelegate; import org.apache.jackrabbit.oak.jcr.delegate.PropertyDelegate; @@ -91,8 +89,8 @@ import org.apache.jackrabbit.oak.jcr.version.VersionHistoryImpl; import org.apache.jackrabbit.oak.jcr.version.VersionImpl; import org.apache.jackrabbit.oak.plugins.identifier.IdentifierManager; import org.apache.jackrabbit.oak.plugins.memory.PropertyStates; +import org.apache.jackrabbit.oak.plugins.nodetype.write.ReadWriteNodeTypeManager; import org.apache.jackrabbit.oak.spi.nodetype.EffectiveNodeType; -import org.apache.jackrabbit.oak.plugins.tree.factories.RootFactory; import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants; import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions; import org.apache.jackrabbit.oak.plugins.tree.TreeUtil; @@ -109,13 +107,6 @@ import org.slf4j.LoggerFactory; */ public class NodeImpl extends ItemImpl implements Node, JackrabbitNode { - /** - * Use an zero length MVP to check read permission on jcr:mixinTypes (OAK-7652) - */ - private static final PropertyState EMPTY_MIXIN_TYPES = PropertyStates.createProperty( - JcrConstants.JCR_MIXINTYPES, Collections.emptyList(), Type.NAMES); - - /** * The maximum returned value for {@link NodeIterator#getSize()}. If there * are more nodes, the method returns -1. @@ -325,7 +316,9 @@ public class NodeImpl extends ItemImpl implements Nod sessionDelegate.performVoid(new ItemWriteOperation("orderBefore") { @Override public void performVoid() throws RepositoryException { - getEffectiveNodeType().checkOrderableChildNodes(); + EffectiveNodeType ent = getNodeTypeManager().getEffectiveNodeType(dlg.getTree()); + ent.checkOrderableChildNodes(); + String oakSrcChildRelPath = getOakPathOrThrowNotFound(srcChildRelPath); String oakDestChildRelPath = null; if (destChildRelPath != null) { @@ -893,7 +886,7 @@ public class NodeImpl extends ItemImpl implements Nod @Override public NodeType perform() throws RepositoryException { Tree tree = node.getTree(); - String primaryTypeName = getPrimaryTypeName(tree); + String primaryTypeName = getNodeTypeManager().getPrimaryTypeName(tree); if (primaryTypeName != null) { return getNodeTypeManager().getNodeType(sessionContext.getJcrName(primaryTypeName)); } else { @@ -915,9 +908,9 @@ public class NodeImpl extends ItemImpl implements Nod public NodeType[] perform() throws RepositoryException { Tree tree = node.getTree(); - Iterator mixinNames = getMixinTypeNames(tree); + ReadWriteNodeTypeManager ntMgr = getNodeTypeManager(); + Iterator mixinNames = ntMgr.getMixinTypeNames(tree).iterator(); if (mixinNames.hasNext()) { - NodeTypeManager ntMgr = getNodeTypeManager(); List mixinTypes = Lists.newArrayList(); while (mixinNames.hasNext()) { mixinTypes.add(ntMgr.getNodeType(sessionContext.getJcrName(mixinNames.next()))); @@ -938,7 +931,7 @@ public class NodeImpl extends ItemImpl implements Nod @Override public Boolean perform() throws RepositoryException { Tree tree = node.getTree(); - return getNodeTypeManager().isNodeType(getPrimaryTypeName(tree), getMixinTypeNames(tree), oakName); + return getNodeTypeManager().isNodeType(tree, oakName); } }); } @@ -1288,38 +1281,6 @@ public class NodeImpl extends ItemImpl implements Nod } //------------------------------------------------------------< internal >--- - @Nullable - private String getPrimaryTypeName(@NotNull Tree tree) { - return TreeUtil.getPrimaryTypeName(tree, getReadOnlyTree(tree)); - } - - @NotNull - private Iterator getMixinTypeNames(@NotNull Tree tree) throws RepositoryException { - if (tree.hasProperty(JcrConstants.JCR_MIXINTYPES) || canReadMixinTypes(tree)) { - return TreeUtil.getMixinTypeNames(tree).iterator(); - } else { - return TreeUtil.getMixinTypeNames(tree, getReadOnlyTree(tree)).iterator(); - } - } - - @NotNull - private LazyValue getReadOnlyTree(@NotNull Tree tree) { - return new LazyValue() { - @Override - protected Tree createValue() { - return RootFactory.createReadOnlyRoot(sessionDelegate.getRoot()).getTree(tree.getPath()); - } - }; - } - - private boolean canReadMixinTypes(@NotNull Tree tree) throws RepositoryException { - return sessionContext.getAccessManager().hasPermissions( - tree, EMPTY_MIXIN_TYPES, Permissions.READ_PROPERTY); - } - - private EffectiveNodeType getEffectiveNodeType() throws RepositoryException { - return getNodeTypeManager().getEffectiveNodeType(dlg.getTree()); - } private Iterator nodeIterator(Iterator childNodes) { return sessionDelegate.sync(transform( diff --git a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java index 58135d5ed9..ea07aed5c2 100644 --- a/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java +++ b/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/WorkspaceImpl.java @@ -41,6 +41,7 @@ import org.apache.jackrabbit.commons.xml.ParsingContentHandler; import org.apache.jackrabbit.oak.api.CommitFailedException; import org.apache.jackrabbit.oak.api.Root; import org.apache.jackrabbit.oak.api.Tree; +import org.apache.jackrabbit.oak.commons.LazyValue; import org.apache.jackrabbit.oak.jcr.delegate.SessionDelegate; import org.apache.jackrabbit.oak.jcr.delegate.WorkspaceDelegate; import org.apache.jackrabbit.oak.jcr.lock.LockDeprecation; @@ -52,7 +53,10 @@ import org.apache.jackrabbit.oak.jcr.xml.ImportHandler; import org.apache.jackrabbit.oak.namepath.NamePathMapper; import org.apache.jackrabbit.oak.plugins.name.ReadWriteNamespaceRegistry; import org.apache.jackrabbit.oak.plugins.nodetype.write.ReadWriteNodeTypeManager; +import org.apache.jackrabbit.oak.plugins.tree.factories.RootFactory; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.xml.sax.ContentHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; @@ -112,6 +116,23 @@ public class WorkspaceImpl implements JackrabbitWorkspace { protected NamePathMapper getNamePathMapper() { return sessionContext; } + + @Nullable + @Override + protected LazyValue getReadOnlyTree(@NotNull Tree tree) { + return new LazyValue() { + @Override + protected Tree createValue() { + return RootFactory.createReadOnlyRoot(sessionDelegate.getRoot()).getTree(tree.getPath()); + } + }; + } + + @NotNull + @Override + protected PermissionProvider getPermissionProvider() { + return sessionDelegate.getPermissionProvider(); + } }; }