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


Reply via email to