You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by to...@apache.org on 2017/05/25 07:51:42 UTC
svn commit: r1796134 - in /jackrabbit/oak/trunk: oak-core/
oak-store-composite/
oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/
oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/
Author: tomekr
Date: Thu May 25 07:51:42 2017
New Revision: 1796134
URL: http://svn.apache.org/viewvc?rev=1796134&view=rev
Log:
OAK-6256: Prevent creating the across-mounts references
Added:
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidator.java
jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidatorProvider.java
jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidatorTest.java
Modified:
jackrabbit/oak/trunk/oak-core/pom.xml
jackrabbit/oak/trunk/oak-store-composite/pom.xml
Modified: jackrabbit/oak/trunk/oak-core/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/pom.xml?rev=1796134&r1=1796133&r2=1796134&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-core/pom.xml Thu May 25 07:51:42 2017
@@ -58,6 +58,7 @@
org.apache.jackrabbit.oak.plugins.index.nodetype,
org.apache.jackrabbit.oak.plugins.index.property,
org.apache.jackrabbit.oak.plugins.index.property.jmx,
+ org.apache.jackrabbit.oak.plugins.index.property.strategy,
org.apache.jackrabbit.oak.plugins.index.reference,
org.apache.jackrabbit.oak.plugins.itemsave,
org.apache.jackrabbit.oak.plugins.lock,
@@ -86,8 +87,10 @@
org.apache.jackrabbit.oak.spi.security.user.util,
org.apache.jackrabbit.oak.spi.xml,
org.apache.jackrabbit.oak.query,
+ org.apache.jackrabbit.oak.query.ast,
org.apache.jackrabbit.oak.query.fulltext,
org.apache.jackrabbit.oak.query.facet,
+ org.apache.jackrabbit.oak.query.index,
org.apache.jackrabbit.oak.security,
org.apache.jackrabbit.oak.util,
</Export-Package>
Modified: jackrabbit/oak/trunk/oak-store-composite/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/pom.xml?rev=1796134&r1=1796133&r2=1796134&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/pom.xml (original)
+++ jackrabbit/oak/trunk/oak-store-composite/pom.xml Thu May 25 07:51:42 2017
@@ -85,6 +85,11 @@
</dependency>
<dependency>
<groupId>org.apache.jackrabbit</groupId>
+ <artifactId>oak-core</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jackrabbit</groupId>
<artifactId>oak-store-spi</artifactId>
<version>${project.version}</version>
</dependency>
Added: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidator.java?rev=1796134&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidator.java (added)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidator.java Thu May 25 07:51:42 2017
@@ -0,0 +1,184 @@
+/*
+ * 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.jackrabbit.oak.composite;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.Multimap;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.index.property.Multiplexers;
+import org.apache.jackrabbit.oak.plugins.index.property.strategy.IndexStoreStrategy;
+import org.apache.jackrabbit.oak.query.QueryEngineSettings;
+import org.apache.jackrabbit.oak.query.index.FilterImpl;
+import org.apache.jackrabbit.oak.spi.commit.DefaultValidator;
+import org.apache.jackrabbit.oak.spi.commit.Validator;
+import org.apache.jackrabbit.oak.spi.mount.Mount;
+import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
+import org.apache.jackrabbit.oak.spi.query.Filter;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import static com.google.common.collect.ImmutableSet.of;
+import static com.google.common.collect.Maps.newHashMap;
+import static org.apache.jackrabbit.JcrConstants.JCR_UUID;
+import static org.apache.jackrabbit.oak.api.CommitFailedException.INTEGRITY;
+import static org.apache.jackrabbit.oak.commons.PathUtils.concat;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_CONTENT_NODE_NAME;
+import static org.apache.jackrabbit.oak.plugins.index.IndexConstants.INDEX_DEFINITIONS_NAME;
+
+public class CrossMountReferenceValidator extends DefaultValidator {
+
+ private static final Filter EMPTY_FILTER = new FilterImpl(null, null, new QueryEngineSettings());
+
+ /** Parent editor, or {@code null} if this is the root editor. */
+ private final CrossMountReferenceValidator parent;
+
+ /** Name of this node, or {@code null} for the root node. */
+ private final String name;
+
+ /** Path of this editor, built lazily in {@link #getPath()}. */
+ private String path;
+
+ /** UUID -> referencable node path */
+ private final Map<String, String> newReferencableNodes;
+
+ /** UUID -> referencing node */
+ private final Multimap<String, String> newReferences;
+
+ private final MountInfoProvider mip;
+
+ private final NodeState uuidDefinition;
+
+ private final Set<IndexStoreStrategy> uuidStores;
+
+ private CrossMountReferenceValidator(CrossMountReferenceValidator parent, String name) {
+ this.name = name;
+ this.parent = parent;
+ this.path = null;
+ this.mip = parent.mip;
+ this.newReferencableNodes = parent.newReferencableNodes;
+ this.newReferences = parent.newReferences;
+ this.uuidDefinition = parent.uuidDefinition;
+ this.uuidStores = parent.uuidStores;
+ }
+
+ public CrossMountReferenceValidator(NodeState root, MountInfoProvider mip) {
+ this.name = null;
+ this.parent = null;
+ this.path = "/";
+ this.mip = mip;
+ this.newReferencableNodes = newHashMap();
+ this.newReferences = ArrayListMultimap.create();
+ this.uuidDefinition = root.getChildNode(INDEX_DEFINITIONS_NAME).getChildNode("uuid");
+ this.uuidStores = Multiplexers.getStrategies(true, mip, uuidDefinition, INDEX_CONTENT_NODE_NAME);
+ }
+
+ @Override
+ public void enter(NodeState before, NodeState after)
+ throws CommitFailedException {
+ }
+
+ @Override
+ public void leave(NodeState before, NodeState after)
+ throws CommitFailedException {
+ if (parent != null) {
+ return;
+ }
+ for (Map.Entry<String, Collection<String>> e : newReferences.asMap().entrySet()) {
+ String uuid = e.getKey();
+ String passivePath = getPathByUuid(uuid);
+ if (passivePath == null) {
+ throw new CommitFailedException(INTEGRITY, 1,
+ "Can't find path for the uuid: " + uuid);
+ }
+ Mount m1 = mip.getMountByPath(passivePath);
+
+ for (String activePath : e.getValue()) {
+ Mount m2 = mip.getMountByPath(activePath);
+ if (!m1.equals(m2)) {
+ throw new CommitFailedException(INTEGRITY, 1,
+ "Unable to reference the node [" + passivePath + "] from node [" + activePath + "]. Referencing across the mounts is not allowed.");
+ }
+ }
+ }
+ }
+
+ private String getPathByUuid(String uuid) {
+ if (newReferencableNodes.containsKey(uuid)) {
+ return newReferencableNodes.get(uuid);
+ }
+ for (IndexStoreStrategy store : uuidStores) {
+ for (String path : store.query(EMPTY_FILTER, null, uuidDefinition, of(uuid))) {
+ return path;
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void propertyAdded(PropertyState after)
+ throws CommitFailedException {
+ checkProperty(after);
+ }
+
+ @Override
+ public void propertyChanged(PropertyState before, PropertyState after)
+ throws CommitFailedException {
+ checkProperty(after);
+ }
+
+ private void checkProperty(PropertyState property) {
+ Type<?> type = property.getType();
+ if (type == Type.REFERENCE) {
+ newReferences.put(property.getValue(Type.REFERENCE), getPath());
+ } else if (type == Type.REFERENCES) {
+ for (String r : property.getValue(Type.REFERENCES)) {
+ newReferences.put(r, getPath());
+ }
+ } else if (type == Type.STRING && JCR_UUID.equals(property.getName())) {
+ newReferencableNodes.put(property.getValue(Type.STRING), getPath());
+ }
+ }
+
+ @Override
+ public Validator childNodeAdded(String name, NodeState after)
+ throws CommitFailedException {
+ return new CrossMountReferenceValidator(this, name);
+ }
+
+ @Override
+ public Validator childNodeChanged(
+ String name, NodeState before, NodeState after)
+ throws CommitFailedException {
+ return new CrossMountReferenceValidator(this, name);
+ }
+
+ /**
+ * Returns the path of this node, building it lazily when first requested.
+ */
+ private String getPath() {
+ if (path == null) {
+ path = concat(parent.getPath(), name);
+ }
+ return path;
+ }
+
+}
Added: jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidatorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidatorProvider.java?rev=1796134&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidatorProvider.java (added)
+++ jackrabbit/oak/trunk/oak-store-composite/src/main/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidatorProvider.java Thu May 25 07:51:42 2017
@@ -0,0 +1,51 @@
+/*
+ * 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.jackrabbit.oak.composite;
+
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Property;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.Service;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.EditorProvider;
+import org.apache.jackrabbit.oak.spi.commit.Validator;
+import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
+import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
+import org.apache.jackrabbit.oak.spi.mount.Mounts;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+
+/**
+ * {@link Validator} which detects references crossing the mount boundaries
+ */
+@Component(label = "Apache Jackrabbit Oak CrossMountReferenceValidatorProvider")
+@Property(name = "type", value = "crossMountRefValidator", propertyPrivate = true)
+@Service({ValidatorProvider.class, EditorProvider.class})
+public class CrossMountReferenceValidatorProvider extends ValidatorProvider {
+
+ @Reference
+ private MountInfoProvider mountInfoProvider = Mounts.defaultMountInfoProvider();
+
+ @Override
+ protected Validator getRootValidator(NodeState before, NodeState after, CommitInfo info) {
+ return new CrossMountReferenceValidator(after, mountInfoProvider);
+ }
+
+ CrossMountReferenceValidatorProvider with(MountInfoProvider mountInfoProvider) {
+ this.mountInfoProvider = mountInfoProvider;
+ return this;
+ }
+}
Added: jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidatorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidatorTest.java?rev=1796134&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidatorTest.java (added)
+++ jackrabbit/oak/trunk/oak-store-composite/src/test/java/org/apache/jackrabbit/oak/composite/CrossMountReferenceValidatorTest.java Thu May 25 07:51:42 2017
@@ -0,0 +1,93 @@
+/*
+ * 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.jackrabbit.oak.composite;
+
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.plugins.index.CompositeIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.IndexUpdateProvider;
+import org.apache.jackrabbit.oak.plugins.index.property.PropertyIndexEditorProvider;
+import org.apache.jackrabbit.oak.plugins.index.reference.ReferenceEditorProvider;
+import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
+import org.apache.jackrabbit.oak.spi.commit.CompositeEditorProvider;
+import org.apache.jackrabbit.oak.spi.commit.EditorHook;
+import org.apache.jackrabbit.oak.spi.mount.MountInfoProvider;
+import org.apache.jackrabbit.oak.spi.mount.Mounts;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.apache.jackrabbit.JcrConstants.JCR_UUID;
+import static org.apache.jackrabbit.oak.InitialContent.INITIAL_CONTENT;
+import static org.apache.jackrabbit.oak.plugins.memory.PropertyStates.createProperty;
+
+public class CrossMountReferenceValidatorTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ private EditorHook hook;
+
+ @Before
+ public void initializeHook() {
+ MountInfoProvider mip = Mounts.newBuilder()
+ .mount("foo", "/a")
+ .build();
+ hook = new EditorHook(new CompositeEditorProvider(
+ new IndexUpdateProvider(new CompositeIndexEditorProvider(
+ new PropertyIndexEditorProvider().with(mip),
+ new ReferenceEditorProvider().with(mip))),
+ new CrossMountReferenceValidatorProvider().with(mip)));
+ }
+
+ @Test
+ public void globalToPrivateReference() throws Exception{
+ NodeState root = INITIAL_CONTENT;
+
+ NodeBuilder builder = root.builder();
+ NodeState before = builder.getNodeState();
+
+ builder.child("a").setProperty(createProperty(JCR_UUID, "u1", Type.STRING));
+ builder.child("b").setProperty(createProperty("foo", "u1", Type.REFERENCE));
+
+ NodeState after = builder.getNodeState();
+
+ thrown.expect(CommitFailedException.class);
+ thrown.expectMessage("OakIntegrity0001: Unable to reference the node [/a] from node [/b]. Referencing across the mounts is not allowed.");
+ hook.processCommit(before, after, CommitInfo.EMPTY);
+ }
+
+ @Test
+ public void privateToGlobalReference() throws Exception{
+ NodeState root = INITIAL_CONTENT;
+
+ NodeBuilder builder = root.builder();
+ NodeState before = builder.getNodeState();
+
+ builder.child("a").setProperty(createProperty("foo", "u1", Type.REFERENCE));
+ builder.child("b").setProperty(createProperty(JCR_UUID, "u1", Type.STRING));
+
+ NodeState after = builder.getNodeState();
+
+ thrown.expect(CommitFailedException.class);
+ thrown.expectMessage("OakIntegrity0001: Unable to reference the node [/b] from node [/a]. Referencing across the mounts is not allowed.");
+ hook.processCommit(before, after, CommitInfo.EMPTY);
+ }
+}