Author: angela Date: Fri May 19 08:31:18 2017 New Revision: 1795596 URL: http://svn.apache.org/viewvc?rev=1795596&view=rev Log: OAK-5355 : Too eager refreshing of tree permissions in SecureNodeBuilder
Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/MutableRootTest.java (with props) jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/SecureNodeBuilderTest.java (with props) jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/TestPermissionProvider.java (with props) Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java?rev=1795596&r1=1795595&r2=1795596&view=diff ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java (original) +++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/core/SecureNodeBuilder.java Fri May 19 08:31:18 2017 @@ -158,9 +158,8 @@ class SecureNodeBuilder implements NodeB public void baseChanged() { checkState(parent == null); - treePermission = null; // trigger re-evaluation of the context + treePermission = null; // trigger re-evaluation rootPermission = null; - getTreePermission(); // sets both tree permissions and root node permissions } @Override @@ -174,11 +173,11 @@ class SecureNodeBuilder implements NodeB return exists() && builder.moveTo(newParent, newName); } - @Override @CheckForNull + @CheckForNull + @Override public PropertyState getProperty(String name) { PropertyState property = builder.getProperty(name); - if (property != null - && new ReadablePropertyPredicate().apply(property)) { + if (new ReadablePropertyPredicate().apply(property)) { return property; } else { return null; @@ -201,7 +200,8 @@ class SecureNodeBuilder implements NodeB } } - @Override @Nonnull + @Nonnull + @Override public Iterable<? extends PropertyState> getProperties() { if (getTreePermission().canReadProperties() || isNew()) { return builder.getProperties(); @@ -215,61 +215,66 @@ class SecureNodeBuilder implements NodeB @Override public boolean getBoolean(@Nonnull String name) { PropertyState property = getProperty(name); - return property != null - && property.getType() == BOOLEAN - && property.getValue(BOOLEAN); + return isType(property, BOOLEAN) && property.getValue(BOOLEAN); } - @Override @CheckForNull + @CheckForNull + @Override public String getString(@Nonnull String name) { PropertyState property = getProperty(name); - if (property != null && property.getType() == STRING) { + if (isType(property, STRING)) { return property.getValue(STRING); } else { return null; } } - @Override @CheckForNull + @CheckForNull + @Override public String getName(@Nonnull String name) { PropertyState property = getProperty(name); - if (property != null && property.getType() == NAME) { + if (isType(property, NAME)) { return property.getValue(NAME); } else { return null; } } - @Override @Nonnull + @Nonnull + @Override public Iterable<String> getNames(@Nonnull String name) { PropertyState property = getProperty(name); - if (property != null && property.getType() == NAMES) { + if (isType(property, NAMES)) { return property.getValue(NAMES); } else { return emptyList(); } } - @Override @Nonnull + @Nonnull + @Override public NodeBuilder setProperty(@Nonnull PropertyState property) { builder.setProperty(property); return this; } - @Override @Nonnull + @Nonnull + @Override public <T> NodeBuilder setProperty(String name, @Nonnull T value) { builder.setProperty(name, value); return this; } - @Override @Nonnull + @Nonnull + @Override public <T> NodeBuilder setProperty( String name, @Nonnull T value, Type<T> type) { builder.setProperty(name, value, type); return this; } - @Override @Nonnull + @Nonnull + @Override public NodeBuilder removeProperty(String name) { if (hasProperty(name)) { // only remove properties that we can see builder.removeProperty(name); @@ -277,16 +282,12 @@ class SecureNodeBuilder implements NodeB return this; } - @Override @Nonnull + @Nonnull + @Override public Iterable<String> getChildNodeNames() { return filter( builder.getChildNodeNames(), - new Predicate<String>() { - @Override - public boolean apply(@Nullable String input) { - return input != null && getChildNode(input).exists(); - } - }); + input -> input != null && getChildNode(input).exists()); } @Override @@ -298,7 +299,8 @@ class SecureNodeBuilder implements NodeB } } - @Override @Nonnull + @Nonnull + @Override public NodeBuilder child(@Nonnull String name) { if (hasChildNode(name)) { return getChildNode(name); @@ -307,13 +309,15 @@ class SecureNodeBuilder implements NodeB } } - @Override @Nonnull + @Nonnull + @Override public NodeBuilder setChildNode(@Nonnull String name) { builder.setChildNode(name); return new SecureNodeBuilder(this, name); } - @Override @Nonnull + @Nonnull + @Override public NodeBuilder setChildNode(@Nonnull String name, @Nonnull NodeState nodeState) { builder.setChildNode(name, nodeState); return new SecureNodeBuilder(this, name); @@ -344,6 +348,7 @@ class SecureNodeBuilder implements NodeB * * @return The permissions for this tree. */ + @Nonnull private TreePermission getTreePermission() { if (treePermission == null || rootPermission != rootBuilder.treePermission) { @@ -360,6 +365,11 @@ class SecureNodeBuilder implements NodeB return treePermission; } + private static boolean isType(@CheckForNull PropertyState property, Type<?> type) { + Type<?> t = (property == null) ? null : property.getType(); + return t == type; + } + //------------------------------------------------------< inner classes >--- /** Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/MutableRootTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/MutableRootTest.java?rev=1795596&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/MutableRootTest.java (added) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/MutableRootTest.java Fri May 19 08:31:18 2017 @@ -0,0 +1,106 @@ +/* + * 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 java.security.Principal; +import java.util.Set; +import javax.annotation.Nonnull; +import javax.security.auth.Subject; + +import org.apache.jackrabbit.oak.api.Root; +import org.apache.jackrabbit.oak.api.Tree; +import org.apache.jackrabbit.oak.commons.PathUtils; +import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore; +import org.apache.jackrabbit.oak.spi.commit.EmptyHook; +import org.apache.jackrabbit.oak.spi.security.OpenSecurityProvider; +import org.apache.jackrabbit.oak.spi.security.SecurityProvider; +import org.apache.jackrabbit.oak.spi.security.authentication.AuthInfoImpl; +import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration; +import org.apache.jackrabbit.oak.spi.security.authorization.OpenAuthorizationConfiguration; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission; +import org.apache.jackrabbit.oak.spi.state.NodeBuilder; +import org.apache.jackrabbit.oak.spi.state.NodeStore; +import org.junit.Before; +import org.junit.Test; +import org.mockito.Mockito; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.when; + +public class MutableRootTest { + + private final NodeStore store = new MemoryNodeStore(); + private final TestPermissionProvider permissionProvider = new TestPermissionProvider(); + + private MutableRoot root; + + @Before + public void before() { + SecurityProvider sp = new OpenSecurityProvider() { + @Nonnull + @Override + public <T> T getConfiguration(@Nonnull Class<T> configClass) { + if (AuthorizationConfiguration.class == configClass) { + return (T) new OpenAuthorizationConfiguration() { + @Nonnull + @Override + public PermissionProvider getPermissionProvider(@Nonnull Root root, @Nonnull String workspaceName, @Nonnull Set<Principal> principals) { + return permissionProvider; + } + }; + } else { + return super.getConfiguration(configClass); + } + } + }; + ContentSessionImpl cs = Mockito.mock(ContentSessionImpl.class); + when(cs.toString()).thenReturn("contentSession"); + when(cs.getAuthInfo()).thenReturn(AuthInfoImpl.EMPTY); + when(cs.getWorkspaceName()).thenReturn("default"); + root = new MutableRoot(store, new EmptyHook(), "default", new Subject(), sp, null, null, cs); + } + + /** + * @see <a href"https://issues.apache.org/jira/browse/OAK-5355">OAK-5355</a> + */ + @Test + public void testCommit() throws Exception { + MutableTree t = root.getTree(PathUtils.ROOT_PATH); + NodeBuilder nb = t.getNodeBuilder(); + assertTrue(nb instanceof SecureNodeBuilder); + + assertEquals(canReadRootTree(t), nb.exists()); + + // commit resets the permissionprovider, which in our test scenario alters + // the 'denyAll' flag. + root.commit(); + + assertEquals(canReadRootTree(t), nb.exists()); + + MutableTree t2 = root.getTree(PathUtils.ROOT_PATH); + NodeBuilder nb2 = t.getNodeBuilder(); + + assertEquals(canReadRootTree(t2), nb.exists()); + assertEquals(nb2.exists(), nb.exists()); + } + + private boolean canReadRootTree(@Nonnull Tree t) { + return permissionProvider.getTreePermission(t, TreePermission.EMPTY).canRead(); + } +} \ No newline at end of file Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/MutableRootTest.java ------------------------------------------------------------------------------ svn:eol-style = native Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/SecureNodeBuilderTest.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/SecureNodeBuilderTest.java?rev=1795596&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/SecureNodeBuilderTest.java (added) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/SecureNodeBuilderTest.java Fri May 19 08:31:18 2017 @@ -0,0 +1,435 @@ +/* + * 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.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; + } + } + +} \ No newline at end of file Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/SecureNodeBuilderTest.java ------------------------------------------------------------------------------ svn:eol-style = native Added: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/TestPermissionProvider.java URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/TestPermissionProvider.java?rev=1795596&view=auto ============================================================================== --- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/TestPermissionProvider.java (added) +++ jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/TestPermissionProvider.java Fri May 19 08:31:18 2017 @@ -0,0 +1,110 @@ +package org.apache.jackrabbit.oak.core; + +import java.util.Set; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +import org.apache.jackrabbit.oak.api.PropertyState; +import org.apache.jackrabbit.oak.api.Tree; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.RepositoryPermission; +import org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission; +import org.apache.jackrabbit.oak.spi.state.NodeState; + +/** + * Dummy permission provider implementation that grants read access to all trees + * that have a name that isn't equal to {@link #NAME_NON_ACCESSIBLE}. + */ +final class TestPermissionProvider implements PermissionProvider { + + static final String NAME_ACCESSIBLE = "accessible"; + static final String NAME_NON_ACCESSIBLE = "notAccessible"; + static final String NAME_NON_EXISTING = "nonExisting"; + + boolean canReadAll = false; + boolean canReadProperties = false; + + boolean denyAll; + + private TreePermission getTreePermission(@Nonnull String name) { + if (denyAll) { + return TreePermission.EMPTY; + } else { + return new TreePermission() { + @Nonnull + @Override + public TreePermission getChildPermission(@Nonnull String childName, @Nonnull NodeState childState) { + return getTreePermission(childName); + } + + @Override + public boolean canRead() { + return canReadAll || !name.contains(NAME_NON_ACCESSIBLE); + } + + @Override + public boolean canRead(@Nonnull PropertyState property) { + return canReadProperties || !property.getName().contains(NAME_NON_ACCESSIBLE); + } + + @Override + public boolean canReadAll() { + return canReadAll; + } + + @Override + public boolean canReadProperties() { + return canReadProperties; + } + + @Override + public boolean isGranted(long permissions) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isGranted(long permissions, @Nonnull PropertyState property) { + throw new UnsupportedOperationException(); + } + }; + } + } + + @Override + public void refresh() { + denyAll = !denyAll; + } + + @Nonnull + @Override + public Set<String> getPrivileges(@Nullable Tree tree) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean hasPrivileges(@Nullable Tree tree, @Nonnull String... privilegeNames) { + throw new UnsupportedOperationException(); + } + + @Nonnull + @Override + public RepositoryPermission getRepositoryPermission() { + throw new UnsupportedOperationException(); + } + + @Nonnull + @Override + public TreePermission getTreePermission(@Nonnull Tree tree, @Nonnull TreePermission parentPermission) { + return getTreePermission(tree.getName()); + } + + @Override + public boolean isGranted(@Nonnull Tree tree, @Nullable PropertyState property, long permissions) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isGranted(@Nonnull String oakPath, @Nonnull String jcrActions) { + throw new UnsupportedOperationException(); + } +} Propchange: jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/core/TestPermissionProvider.java ------------------------------------------------------------------------------ svn:eol-style = native