Author: stillalex
Date: Thu Jun 15 14:27:16 2017
New Revision: 1798839
URL: http://svn.apache.org/viewvc?rev=1798839&view=rev
Log:
OAK-6349 Randomized permission tests
Added:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/AbstractPermissionRandomTestIT.java
(with props)
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/DefaultPermissionRandomTestIT.java
(with props)
Added:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/AbstractPermissionRandomTestIT.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/AbstractPermissionRandomTestIT.java?rev=1798839&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/AbstractPermissionRandomTestIT.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/AbstractPermissionRandomTestIT.java
Thu Jun 15 14:27:16 2017
@@ -0,0 +1,327 @@
+/*
+ * 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.security.authorization.permission;
+
+import static org.apache.jackrabbit.JcrConstants.NT_UNSTRUCTURED;
+import static
org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants.JCR_READ;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertArrayEquals;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Random;
+import java.util.Set;
+import java.util.UUID;
+
+import javax.annotation.Nonnull;
+import javax.jcr.Session;
+import javax.jcr.security.AccessControlManager;
+
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.user.Group;
+import
org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+import
org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
+import
org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider;
+import
org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions;
+import
org.apache.jackrabbit.oak.spi.security.authorization.permission.RepositoryPermission;
+import
org.apache.jackrabbit.oak.spi.security.authorization.permission.TreePermission;
+import org.junit.Test;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+
+/**
+ * Randomized PermissionStore test. It generates a random structure (1110
+ * nodes), samples 10% of the paths for setting 'user' allow read, for setting
+ * 'user' deny read, 10% for setting 'group' allow read and 10% for setting
+ * 'group' deny read.
+ * <p>
+ * For testing a custom implementation against the known evaluation rules,
+ * override the {@link #getSecurityConfigParameters()} method.
+ * <p>
+ * For testing a custom implementation against the default implementation,
+ * override the {@link #candidatePermissionProvider(Root, String, Set)}.
+ *
+ */
+public abstract class AbstractPermissionRandomTestIT extends
AbstractSecurityTest {
+
+ protected final long seed = new Random().nextLong();
+ private final Random random = new Random(seed);
+ protected final String testPath = "testPath" + random.nextInt();
+
+ private List<String> paths = new ArrayList<>();
+
+ protected final Set<String> allowU = Sets.newHashSet();
+ protected final Set<String> denyU = Sets.newHashSet();
+ protected final Set<String> allowG = Sets.newHashSet();
+ protected final Set<String> denyG = Sets.newHashSet();
+
+ private ContentSession testSession;
+ private final String groupId = "gr" + UUID.randomUUID();
+
+ @Override
+ public void before() throws Exception {
+ super.before();
+
+ Tree rootNode = root.getTree("/");
+ Tree testNode = TreeUtil.getOrAddChild(rootNode, testPath,
NT_UNSTRUCTURED);
+
+ // Setup 1110x
+ create(testNode, 10, 0, 3, paths);
+ root.commit();
+
+ Collections.sort(paths);
+ int sampleSize = paths.size() / 10;
+
+ sample(paths, sampleSize, random, allowU);
+ sample(paths, sampleSize, random, denyU);
+ sample(paths, sampleSize, random, allowG);
+ sample(paths, sampleSize, random, denyG);
+ }
+
+ @Override
+ protected ConfigurationParameters getSecurityConfigParameters() {
+ return ConfigurationParameters.EMPTY;
+ }
+
+ protected PermissionProvider candidatePermissionProvider(@Nonnull Root
root, @Nonnull String workspaceName,
+ @Nonnull Set<Principal> principals) {
+ return new SetsPP(allowU, denyU, allowG, denyG);
+ }
+
+ private static void create(Tree t, int count, int lvl, int maxlvl,
List<String> paths) throws Exception {
+ if (lvl == maxlvl) {
+ return;
+ }
+ for (int i = 0; i < count; i++) {
+ Tree c = TreeUtil.addChild(t, "n" + i, NT_UNSTRUCTURED);
+ paths.add(c.getPath());
+ create(c, count, lvl + 1, maxlvl, paths);
+ }
+ }
+
+ protected static void sample(List<String> paths, int size, Random random,
Set<String> sample) {
+ assertTrue(size > 0 && size <= paths.size());
+ for (int i = 0; i < size; i++) {
+ int index = random.nextInt(paths.size());
+ String path = paths.get(index);
+ sample.add(path);
+ }
+ }
+
+ @Test
+ public void testRandomRead() throws Exception {
+ Principal u = getTestUser().getPrincipal();
+ Group group = getUserManager(root).createGroup(groupId);
+ group.addMember(getTestUser());
+ Principal g = group.getPrincipal();
+
+ // set user allow read
+ for (String path : allowU) {
+ setPrivileges(u, path, true, JCR_READ);
+ }
+ // set user deny read
+ for (String path : denyU) {
+ setPrivileges(u, path, false, JCR_READ);
+ }
+ // set group allow read
+ for (String path : allowG) {
+ setPrivileges(g, path, true, JCR_READ);
+ }
+ // set group deny read
+ for (String path : denyG) {
+ setPrivileges(g, path, false, JCR_READ);
+ }
+
+ testSession = createTestSession();
+ Root testRoot = testSession.getLatestRoot();
+
+ AuthorizationConfiguration acConfig =
getConfig(AuthorizationConfiguration.class);
+ PermissionProvider pp = acConfig.getPermissionProvider(testRoot,
testSession.getWorkspaceName(),
+ testSession.getAuthInfo().getPrincipals());
+
+ PermissionProvider candidate = candidatePermissionProvider(testRoot,
testSession.getWorkspaceName(),
+ testSession.getAuthInfo().getPrincipals());
+ boolean isSetImpl = candidate instanceof SetsPP;
+
+ for (String path : paths) {
+ Tree t = testRoot.getTree(path);
+
+ boolean hasPrivileges0 = pp.hasPrivileges(t, JCR_READ);
+ boolean isGrantedA0 = pp.isGranted(t.getPath(),
Session.ACTION_READ);
+ boolean isGrantedP0 = pp.isGranted(t, null, Permissions.READ);
+ String[] privs0 = pp.getPrivileges(t).toArray(new String[] {});
+ Arrays.sort(privs0);
+
+ boolean hasPrivileges1 = candidate.hasPrivileges(t, JCR_READ);
+ boolean isGrantedA1 = candidate.isGranted(t.getPath(),
Session.ACTION_READ);
+ boolean isGrantedP1 = candidate.isGranted(t, null,
Permissions.READ);
+ String[] privs1 = candidate.getPrivileges(t).toArray(new String[]
{});
+ Arrays.sort(privs1);
+
+ if (isSetImpl) {
+ assertTrue("Unexpected #hasPrivileges on [" + path + "]
expecting " + hasPrivileges1 + " got "
+ + hasPrivileges0 + ", seed " + seed, hasPrivileges1 ==
hasPrivileges0);
+ assertTrue("Unexpected #isGranted on [" + path + "] expecting
" + isGrantedA1 + " got " + isGrantedA0
+ + ", seed " + seed, isGrantedA1 == isGrantedA0);
+ assertTrue("Unexpected #isGranted on [" + path + "] expecting
" + isGrantedP1 + " got " + isGrantedP0
+ + ", seed " + seed, isGrantedP1 == isGrantedP0);
+ assertArrayEquals(privs1, privs0);
+
+ } else {
+ assertTrue("Unexpected #hasPrivileges on [" + path + "]
expecting " + hasPrivileges0 + " got "
+ + hasPrivileges1 + ", seed " + seed, hasPrivileges1 ==
hasPrivileges0);
+ assertTrue("Unexpected #isGranted on [" + path + "] expecting
" + isGrantedA0 + " got " + isGrantedA1
+ + ", seed " + seed, isGrantedA1 == isGrantedA0);
+ assertTrue("Unexpected #isGranted on [" + path + "] expecting
" + isGrantedP0 + " got " + isGrantedP1
+ + ", seed " + seed, isGrantedP1 == isGrantedP0);
+ assertArrayEquals(privs0, privs1);
+ }
+
+ }
+ }
+
+ @Override
+ public void after() throws Exception {
+ try {
+ if (testSession != null) {
+ testSession.close();
+ }
+ assertTrue(root.getTree("/" + testPath).remove());
+ root.commit();
+ } finally {
+ super.after();
+ }
+ }
+
+ private void setPrivileges(Principal principal, String path, boolean
allow, String... privileges) throws Exception {
+ AccessControlManager acm = getAccessControlManager(root);
+ JackrabbitAccessControlList acl =
AccessControlUtils.getAccessControlList(acm, path);
+ acl.addEntry(principal, privilegesFromNames(privileges), allow);
+ acm.setPolicy(path, acl);
+ root.commit();
+ }
+
+ private static class SetsPP implements PermissionProvider {
+
+ public SetsPP(Set<String> allowU, Set<String> denyU, Set<String>
allowG, Set<String> denyG) {
+ this.allowU = allowU;
+ this.denyU = denyU;
+ this.allowG = allowG;
+ this.denyG = denyG;
+ }
+
+ protected final Set<String> allowU;
+ protected final Set<String> denyU;
+ protected final Set<String> allowG;
+ protected final Set<String> denyG;
+
+ @Override
+ public void refresh() {
+ }
+
+ @Override
+ public Set<String> getPrivileges(Tree tree) {
+ if (canRead(tree.getPath())) {
+ return ImmutableSet.of(JCR_READ);
+ } else {
+ return ImmutableSet.of();
+ }
+ }
+
+ @Override
+ public boolean hasPrivileges(Tree tree, String... privilegeNames) {
+ assertTrue("Implemened only for JCR_READ",
+ privilegeNames.length == 1 &&
privilegeNames[0].equals(JCR_READ));
+ return canRead(tree.getPath());
+ }
+
+ @Override
+ public RepositoryPermission getRepositoryPermission() {
+ throw new RuntimeException("unimplemented");
+ }
+
+ @Override
+ public TreePermission getTreePermission(Tree tree, TreePermission
parentPermission) {
+ throw new RuntimeException("unimplemented");
+ }
+
+ @Override
+ public boolean isGranted(Tree tree, PropertyState property, long
permissions) {
+ assertTrue("Implemened only for Permissions.READ on trees",
+ property == null && permissions == Permissions.READ);
+ return canRead(tree.getPath());
+ }
+
+ @Override
+ public boolean isGranted(String oakPath, String jcrActions) {
+ assertTrue("Implemened only for Session.ACTION_READ",
jcrActions.equals(Session.ACTION_READ));
+ return canRead(oakPath);
+ }
+
+ private boolean canRead(String p) {
+
+ String deny = extractStatus(p, denyU);
+ String allow = extractStatus(p, allowU);
+ String gdeny = extractStatus(p, denyG);
+ String gallow = extractStatus(p, allowG);
+
+ if (deny != null) {
+ if (allow != null) {
+ return deny.length() < allow.length();
+ } else {
+ return false;
+ }
+
+ } else if (allow != null) {
+ return true;
+
+ } else if (gdeny != null) {
+ if (gallow != null) {
+ return gdeny.length() < gallow.length();
+ } else {
+ return false;
+ }
+
+ } else {
+ return gallow != null;
+ }
+ }
+
+ private static String extractStatus(String p, Set<String> paths) {
+ String res = null;
+ int len = 0;
+ for (String path : paths) {
+ if (p.contains(path) && len < path.length()) {
+ res = path;
+ len = path.length();
+ }
+ }
+ return res;
+ }
+ }
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/AbstractPermissionRandomTestIT.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/DefaultPermissionRandomTestIT.java
URL:
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/DefaultPermissionRandomTestIT.java?rev=1798839&view=auto
==============================================================================
---
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/DefaultPermissionRandomTestIT.java
(added)
+++
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/DefaultPermissionRandomTestIT.java
Thu Jun 15 14:27:16 2017
@@ -0,0 +1,21 @@
+/*
+ * 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.security.authorization.permission;
+
+public class DefaultPermissionRandomTestIT extends
AbstractPermissionRandomTestIT {
+
+}
\ No newline at end of file
Propchange:
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/DefaultPermissionRandomTestIT.java
------------------------------------------------------------------------------
svn:eol-style = native