| /* |
| * 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; |
| } |
| } |
| |
| } |