blob: 6c553135949ab63d3733a8bf3dcf62f78004b449 [file] [log] [blame]
/*
* 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.core;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.commons.LazyValue;
import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
import org.apache.jackrabbit.oak.spi.commit.CommitInfo;
import org.apache.jackrabbit.oak.spi.commit.EmptyHook;
import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
import org.junit.Before;
import org.junit.Test;
import static org.apache.jackrabbit.oak.core.TestPermissionProvider.NAME_ACCESSIBLE;
import static org.apache.jackrabbit.oak.core.TestPermissionProvider.NAME_NON_ACCESSIBLE;
import static org.apache.jackrabbit.oak.core.TestPermissionProvider.NAME_NON_EXISTING;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
public class SecureNodeBuilderTest {
private final NodeStore store = new MemoryNodeStore();
private final TestPermissionProvider permissionProvider = new TestPermissionProvider();
private SecureNodeBuilder secureNodeBuilder;
@Before
public void before() throws Exception {
NodeBuilder rootBuilder = store.getRoot().builder();
rootBuilder.setProperty("prop", "value").setProperty(NAME_NON_ACCESSIBLE, "value");
rootBuilder.child(NAME_ACCESSIBLE).setProperty("prop", "value").setProperty(NAME_NON_ACCESSIBLE, "value");
rootBuilder.child(NAME_NON_ACCESSIBLE).setProperty("prop", "value").setProperty(NAME_NON_ACCESSIBLE, "value");
store.merge(rootBuilder, new EmptyHook(), new CommitInfo("id", null));
rootBuilder = store.getRoot().builder();
secureNodeBuilder = new SecureNodeBuilder(rootBuilder, new LazyValue<PermissionProvider>() {
@Override
protected PermissionProvider createValue() {
return permissionProvider;
}
});
}
@Test
public void testGetChildNodeNonExisting() {
NodeBuilder child = secureNodeBuilder.getChildNode(NAME_NON_EXISTING);
assertTrue(child instanceof SecureNodeBuilder);
}
@Test
public void testGetChildNode() {
NodeBuilder child = secureNodeBuilder.getChildNode(NAME_ACCESSIBLE);
assertTrue(child instanceof SecureNodeBuilder);
assertTrue(child.exists());
}
@Test
public void testGetChildNodeNonAccessible() {
NodeBuilder child = secureNodeBuilder.getChildNode(NAME_NON_ACCESSIBLE);
assertTrue(child instanceof SecureNodeBuilder);
}
@Test
public void testExists() {
assertTrue(secureNodeBuilder.exists());
}
@Test
public void testExistsNonExisting() {
assertFalse(secureNodeBuilder.getChildNode(NAME_NON_EXISTING).exists());
}
@Test
public void testExistsAccessible() {
assertTrue(secureNodeBuilder.getChildNode(NAME_ACCESSIBLE).exists());
}
@Test
public void testExistsNonAccessible() {
assertFalse(secureNodeBuilder.getChildNode(NAME_NON_ACCESSIBLE).exists());
}
@Test
public void testGetBaseState() {
NodeState ns = secureNodeBuilder.getBaseState();
assertTrue(ns instanceof SecureNodeState);
}
@Test
public void testGetBaseStateNonExisting() {
NodeState ns = secureNodeBuilder.getChildNode(NAME_NON_EXISTING).getBaseState();
assertTrue(ns instanceof SecureNodeState);
}
@Test
public void testGetBaseStateNonAccessible() {
NodeState ns = secureNodeBuilder.getChildNode(NAME_NON_ACCESSIBLE).getBaseState();
assertTrue(ns instanceof SecureNodeState);
}
@Test
public void testGetNodeState() {
NodeState ns = secureNodeBuilder.getNodeState();
assertTrue(ns instanceof SecureNodeState);
}
@Test
public void testGetNodeStateNonExisting() {
NodeState ns = secureNodeBuilder.getChildNode(NAME_NON_EXISTING).getNodeState();
assertTrue(ns instanceof SecureNodeState);
}
@Test
public void testGetNodeStateNonAccessible() {
NodeState ns = secureNodeBuilder.getChildNode(NAME_NON_ACCESSIBLE).getNodeState();
assertTrue(ns instanceof SecureNodeState);
}
/**
* Illustrating usage of {@link SecureNodeBuilder#baseChanged()} as it is
* currently present with {@link MutableRoot#commit()}, {@link MutableRoot#rebase()}
* and {@link MutableRoot#refresh()}: baseChanged is call <strong>before</strong>
* the permission provider is refreshed, which depending on the implementation
* may lead to a stale {@code TreePermission} being obtained with the non-lazy
* refresh as described in OAK-5355.
*
* @see <a href"https://issues.apache.org/jira/browse/OAK-5355">OAK-5355</a>
*/
@Test
public void testBaseChanged() {
secureNodeBuilder.baseChanged();
// change the behavior of the permission provider to assure that subsequent
// calls are always reading the most up to date information
try {
permissionProvider.denyAll = true;
assertFalse(secureNodeBuilder.exists());
assertFalse(secureNodeBuilder.hasChildNode(NAME_ACCESSIBLE));
assertFalse(secureNodeBuilder.hasProperty("prop"));
assertFalse(secureNodeBuilder.isNew());
assertFalse(secureNodeBuilder.getBaseState().exists());
assertFalse(secureNodeBuilder.getNodeState().exists());
} finally {
permissionProvider.denyAll = false;
}
}
@Test
public void testHasProperty() {
assertTrue(secureNodeBuilder.hasProperty("prop"));
assertTrue(secureNodeBuilder.getChildNode(NAME_ACCESSIBLE).hasProperty("prop"));
assertTrue(secureNodeBuilder.getChildNode(NAME_NON_ACCESSIBLE).hasProperty("prop"));
assertFalse(secureNodeBuilder.getChildNode(NAME_NON_EXISTING).hasProperty("prop"));
}
@Test
public void testHasPropertyNonAccessible() {
assertFalse(secureNodeBuilder.hasProperty(NAME_NON_ACCESSIBLE));
assertFalse(secureNodeBuilder.getChildNode(NAME_ACCESSIBLE).hasProperty(NAME_NON_ACCESSIBLE));
assertFalse(secureNodeBuilder.getChildNode(NAME_NON_ACCESSIBLE).hasProperty(NAME_NON_ACCESSIBLE));
assertFalse(secureNodeBuilder.getChildNode(NAME_NON_EXISTING).hasProperty(NAME_NON_ACCESSIBLE));
}
@Test
public void testHasPropertyNonExisting() {
assertFalse(secureNodeBuilder.hasProperty(NAME_NON_EXISTING));
assertFalse(secureNodeBuilder.getChildNode(NAME_ACCESSIBLE).hasProperty(NAME_NON_EXISTING));
assertFalse(secureNodeBuilder.getChildNode(NAME_NON_ACCESSIBLE).hasProperty(NAME_NON_EXISTING));
assertFalse(secureNodeBuilder.getChildNode(NAME_NON_EXISTING).hasProperty(NAME_NON_EXISTING));
}
@Test
public void testGetProperty() {
assertNotNull(secureNodeBuilder.getProperty("prop"));
assertNotNull(secureNodeBuilder.getChildNode(NAME_ACCESSIBLE).getProperty("prop"));
assertNotNull(secureNodeBuilder.getChildNode(NAME_NON_ACCESSIBLE).getProperty("prop"));
assertNull(secureNodeBuilder.getChildNode(NAME_NON_EXISTING).getProperty("prop"));
}
@Test
public void testGetPropertyNonAccessible() {
assertNull(secureNodeBuilder.getProperty(NAME_NON_ACCESSIBLE));
assertNull(secureNodeBuilder.getChildNode(NAME_ACCESSIBLE).getProperty(NAME_NON_ACCESSIBLE));
assertNull(secureNodeBuilder.getChildNode(NAME_NON_ACCESSIBLE).getProperty(NAME_NON_ACCESSIBLE));
assertNull(secureNodeBuilder.getChildNode(NAME_NON_EXISTING).getProperty(NAME_NON_ACCESSIBLE));
}
@Test
public void testGetPropertyNonExisting() {
assertNull(secureNodeBuilder.getProperty(NAME_NON_EXISTING));
assertNull(secureNodeBuilder.getChildNode(NAME_ACCESSIBLE).getProperty(NAME_NON_EXISTING));
assertNull(secureNodeBuilder.getChildNode(NAME_NON_ACCESSIBLE).getProperty(NAME_NON_EXISTING));
assertNull(secureNodeBuilder.getChildNode(NAME_NON_EXISTING).getProperty(NAME_NON_EXISTING));
}
@Test
public void testGetPropertyCount() {
assertEquals(1, secureNodeBuilder.getPropertyCount());
assertEquals(1, secureNodeBuilder.getChildNode(NAME_ACCESSIBLE).getPropertyCount());
assertEquals(1, secureNodeBuilder.getChildNode(NAME_NON_ACCESSIBLE).getPropertyCount());
assertEquals(0, secureNodeBuilder.getChildNode(NAME_NON_EXISTING).getPropertyCount());
}
@Test
public void testGetPropertyCountCanReadProperties() {
try {
permissionProvider.canReadProperties = true;
assertEquals(2, secureNodeBuilder.getPropertyCount());
assertEquals(2, secureNodeBuilder.getChildNode(NAME_ACCESSIBLE).getPropertyCount());
assertEquals(2, secureNodeBuilder.getChildNode(NAME_NON_ACCESSIBLE).getPropertyCount());
assertEquals(0, secureNodeBuilder.getChildNode(NAME_NON_EXISTING).getPropertyCount());
} finally {
permissionProvider.canReadProperties = false;
}
}
@Test
public void testGetProperties() {
assertEquals(1, Iterables.size(secureNodeBuilder.getProperties()));
assertEquals(1, Iterables.size(secureNodeBuilder.getChildNode(NAME_ACCESSIBLE).getProperties()));
assertEquals(1, Iterables.size(secureNodeBuilder.getChildNode(NAME_NON_ACCESSIBLE).getProperties()));
assertEquals(0, Iterables.size(secureNodeBuilder.getChildNode(NAME_NON_EXISTING).getProperties()));
}
@Test
public void testGetPropertiesCanReadProperties() {
try {
permissionProvider.canReadProperties = true;
assertEquals(2, Iterables.size(secureNodeBuilder.getProperties()));
assertEquals(2, Iterables.size(secureNodeBuilder.getChildNode(NAME_ACCESSIBLE).getProperties()));
assertEquals(2, Iterables.size(secureNodeBuilder.getChildNode(NAME_NON_ACCESSIBLE).getProperties()));
assertEquals(0, Iterables.size(secureNodeBuilder.getChildNode(NAME_NON_EXISTING).getProperties()));
} finally {
permissionProvider.canReadProperties = false;
}
}
@Test
public void testGetPropertiesAfterSet() {
secureNodeBuilder.setProperty(PropertyStates.createProperty("another", ImmutableList.of("v", "v2"), Type.STRINGS));
assertEquals(2, Iterables.size(secureNodeBuilder.getProperties()));
}
@Test
public void testGetPropertiesAfterRemoval() {
secureNodeBuilder.removeProperty("prop");
assertEquals(0, Iterables.size(secureNodeBuilder.getProperties()));
}
@Test
public void testGetBoolean() {
assertFalse(secureNodeBuilder.getBoolean("prop"));
assertFalse(secureNodeBuilder.getBoolean(NAME_NON_EXISTING));
assertFalse(secureNodeBuilder.getBoolean(NAME_NON_ACCESSIBLE));
}
@Test
public void testGetBooleanTypeBoolean() {
secureNodeBuilder.setProperty("boolean", true, Type.BOOLEAN);
assertTrue(secureNodeBuilder.getBoolean("boolean"));
}
@Test
public void testGetBooleanTypeBooleans() {
secureNodeBuilder.setProperty("booleans", ImmutableList.of(true, false), Type.BOOLEANS);
assertFalse(secureNodeBuilder.getBoolean("booleans"));
}
@Test
public void testGetString() {
assertEquals("value", secureNodeBuilder.getString("prop"));
assertNull(secureNodeBuilder.getString(NAME_NON_EXISTING));
assertNull(secureNodeBuilder.getString(NAME_NON_ACCESSIBLE));
}
@Test
public void testGetStringTypeStrings() {
secureNodeBuilder.setProperty("strings", ImmutableList.of("a", "b"), Type.STRINGS);
assertNull(secureNodeBuilder.getString("strings"));
}
@Test
public void testGetStringTypeLong() {
secureNodeBuilder.setProperty("long", Long.MAX_VALUE, Type.LONG);
assertNull(secureNodeBuilder.getString("long"));
}
@Test
public void testGetName() {
assertNull(secureNodeBuilder.getName("prop"));
assertNull(secureNodeBuilder.getName(NAME_NON_EXISTING));
assertNull(secureNodeBuilder.getName(NAME_NON_ACCESSIBLE));
}
@Test
public void testGetNameTypeNames() {
secureNodeBuilder.setProperty("names", ImmutableList.of("a", "b"), Type.NAMES);
assertNull(secureNodeBuilder.getName("names"));
}
@Test
public void testGetNameTypeName() {
secureNodeBuilder.setProperty("name", "value", Type.NAME);
assertEquals("value", secureNodeBuilder.getName("name"));
}
@Test
public void testGetNames() {
assertEquals(0, Iterables.size(secureNodeBuilder.getNames("prop")));
assertEquals(0, Iterables.size(secureNodeBuilder.getNames(NAME_NON_EXISTING)));
assertEquals(0, Iterables.size(secureNodeBuilder.getNames(NAME_NON_ACCESSIBLE)));
}
@Test
public void testGetNamesTypeNames() {
Iterable<String> names = ImmutableList.of("a", "b");
secureNodeBuilder.setProperty("names", names, Type.NAMES);
assertTrue(Iterables.elementsEqual(names, secureNodeBuilder.getNames("names")));
}
@Test
public void testGetNamesTypeName() {
secureNodeBuilder.setProperty("name", "value", Type.NAME);
assertEquals(0, Iterables.size(secureNodeBuilder.getNames("name")));
}
@Test
public void testSetProperty() {
secureNodeBuilder.setProperty("another", "value");
assertTrue(secureNodeBuilder.hasProperty("another"));
}
@Test
public void testSetPropertyReturnsSame() {
assertSame(secureNodeBuilder, secureNodeBuilder.setProperty("another", "value"));
}
@Test
public void testSetPropertyModifiedNonAccessible() {
secureNodeBuilder.setProperty(NAME_NON_ACCESSIBLE, "anothervalue");
// modified property must exist irrespective of permission eval
assertTrue(secureNodeBuilder.hasProperty(NAME_NON_ACCESSIBLE));
}
@Test
public void testSetPropertyNewNonAccessible() {
String name = NAME_NON_ACCESSIBLE+"-new";
secureNodeBuilder.setProperty(name, "value");
// new property must exist irrespective of permission eval
assertTrue(secureNodeBuilder.hasProperty(name));
}
@Test
public void testRemoveProperty() {
secureNodeBuilder.removeProperty("prop");
assertFalse(secureNodeBuilder.hasProperty("prop"));
}
@Test
public void testRemovePropertyNonAccessible() {
secureNodeBuilder.removeProperty(NAME_NON_ACCESSIBLE);
// verify that property has not been removed
try {
permissionProvider.canReadProperties = true;
assertTrue(secureNodeBuilder.hasProperty(NAME_NON_ACCESSIBLE));
} finally {
permissionProvider.canReadProperties = false;
}
}
@Test
public void testRemovePropertyReturnsSame() {
assertSame(secureNodeBuilder, secureNodeBuilder.removeProperty("prop"));
}
@Test
public void testHasChildNode() {
assertTrue(secureNodeBuilder.hasChildNode(NAME_ACCESSIBLE));
}
@Test
public void testHasChildNodeNonAccessible() {
assertFalse(secureNodeBuilder.hasChildNode(NAME_NON_ACCESSIBLE));
}
@Test
public void testHasChildNodeNonExisting() {
assertFalse(secureNodeBuilder.hasChildNode(NAME_NON_EXISTING));
}
@Test
public void testGetChildNodeCount() {
assertEquals(1, secureNodeBuilder.getChildNodeCount(Long.MAX_VALUE));
}
@Test
public void testGetChildNodeCountCanReadAll() {
try {
permissionProvider.canReadAll = true;
assertEquals(2, secureNodeBuilder.getChildNodeCount(Long.MAX_VALUE));
} finally {
permissionProvider.canReadAll = false;
}
}
}