You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2015/06/18 16:30:17 UTC
svn commit: r1686235 [3/6] - in /jackrabbit/oak/trunk: ./
oak-doc/src/site/markdown/ oak-exercise/ oak-exercise/src/
oak-exercise/src/main/ oak-exercise/src/main/java/
oak-exercise/src/main/java/org/ oak-exercise/src/main/java/org/apache/
oak-exercise/...
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L4_EffectivePoliciesTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L4_EffectivePoliciesTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L4_EffectivePoliciesTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L4_EffectivePoliciesTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,310 @@
+/*
+ * 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.accesscontrol;
+
+import java.security.Principal;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.Privilege;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlManager;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.security.ExerciseUtility;
+import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
+import org.apache.jackrabbit.test.AbstractJCRTest;
+import org.apache.jackrabbit.test.NotExecutableException;
+
+/**
+ * <pre>
+ * Module: Authorization (Access Control Management)
+ * =============================================================================
+ *
+ * Title: Effective Policies
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * Undestand the meaning and nature of retrieving the effective policies for
+ * a given path or set of principals.
+ *
+ * Exercises:
+ *
+ * - {@link #testGetEffectivePolicies()}
+ * This test create policies at the test root and its child node.
+ * Fix the test such that the expected number of effective policies is correct.
+ *
+ * - {@link #testGetEffectivePoliciesAtNodeTypeRoot()}
+ * Implementation specific test retrieve the effective policies for the
+ * node type root node. Fix the test such that it passes.
+ *
+ * Question: What is the expected result?
+ * Question: If there are effective policies, can you explain why?
+ * Question: Can you also describe the nature of the effective policies?
+ *
+ * - {@link #testGetEffectivePoliciesNewPolicy()}
+ * Test case illustrating the nature of the effective policies.
+ * Fix the case such that the assertion is correct.
+ *
+ * - {@link #testGetEffectivePoliciesByPrincipal()}
+ * Test case illustrating the usage of
+ * {@link org.apache.jackrabbit.api.security.JackrabbitAccessControlManager#getEffectivePolicies(java.util.Set)}
+ * Fill in the expected number of effective policies and explain your expectations.
+ *
+ *
+ * Additional Exercises
+ * -----------------------------------------------------------------------------
+ *
+ * The following exercises use a test session with limited access rights to
+ * retrieve the effective policies.
+ *
+ * - {@link #testSessionGetEffectivePolicies()}
+ * In this case the effective policies are retrieved with a test session that
+ * has limited access. Insert the expected number of effective policies and
+ * explain the result.
+ *
+ * - {@link #testSessionGetEffectivePoliciesWithoutPrivilege()}
+ * Again the test session with limited access rights is used to retrieve the
+ * effective policies. Fix the test-case and explain the results based on
+ * the implementation you can find in {@link org.apache.jackrabbit.oak.security.authorization.accesscontrol.AccessControlManagerImpl}.
+ *
+ * - {@link #testSessionGetEffectivePoliciesByPrincipal()}
+ * The test session with limited access is used to retrieve effective policies
+ * by principal. Fix the test case and explain the expected result.
+ *
+ * - {@link #testSessionGetEffectivePoliciesByPrincipalWithoutPrivileges()}
+ * The same test case again but the test session is not granted jcr:readAccessControl
+ * privilege. Complete the test-case and explain the result.
+ *
+ * - For these additional tests:
+ * Compare the results with what is exposed when using an admin session with
+ * full access everywhere.
+ *
+ * Question: What are the implications for usage/usability of effective policies in a productive environment?
+ *
+ *
+ * Advanced Exercise
+ * -----------------------------------------------------------------------------
+ *
+ * The JCR specification declares the methods to retrieve effective policies as
+ * 'besteffort'. Discuss the meaning of this and try to imagine implementations
+ * where fullfilling this (vague) API contract might not be feasible or not
+ * even be sensible.
+ *
+ * </pre>
+ *
+ * @see javax.jcr.security.AccessControlManager#getEffectivePolicies(String)
+ * @see org.apache.jackrabbit.api.security.JackrabbitAccessControlManager#getEffectivePolicies(java.util.Set)
+ */
+public class L4_EffectivePoliciesTest extends AbstractJCRTest {
+
+ private String childPath;
+
+ private JackrabbitAccessControlManager acMgr;
+ private JackrabbitAccessControlList acl;
+
+ private User testUser;
+ private Principal testPrincipal;
+ private Privilege[] testPrivileges;
+
+ private Session testSession;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ Node child = testRootNode.addNode(nodeName1);
+ childPath = child.getPath();
+
+ testUser = ExerciseUtility.createTestUser(((JackrabbitSession) superuser).getUserManager());
+ testPrincipal = testUser.getPrincipal();
+ superuser.save();
+
+ acMgr = (JackrabbitAccessControlManager) superuser.getAccessControlManager();
+ acl = AccessControlUtils.getAccessControlList(superuser, testRoot);
+ if (acl == null) {
+ throw new NotExecutableException();
+ }
+
+ testPrivileges = AccessControlUtils.privilegesFromNames(acMgr, Privilege.JCR_READ, Privilege.JCR_WRITE);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ if (testSession != null && testSession.isLive()) {
+ testSession.logout();
+ }
+ if (testUser != null) {
+ testUser.remove();
+ superuser.save();
+ }
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ private JackrabbitAccessControlList setupPolicy(String path, Privilege[] privileges, Principal principal) throws RepositoryException, NotExecutableException {
+ JackrabbitAccessControlList policy = AccessControlUtils.getAccessControlList(acMgr, path);
+ if (policy != null) {
+ policy.addEntry(principal, privileges, true);
+ acMgr.setPolicy(path, policy);
+ } else {
+ throw new NotExecutableException();
+ }
+ return policy;
+ }
+
+ private Session getTestSession() throws RepositoryException {
+ return superuser.getRepository().login(ExerciseUtility.getTestCredentials(testUser.getID()));
+ }
+
+ public void testGetEffectivePolicies() throws Exception {
+ AccessControlPolicy[] policies = acMgr.getEffectivePolicies(testRoot);
+ int expectedLength = -1; // EXERCISE
+ assertEquals(expectedLength, policies.length);
+
+ setupPolicy(testRoot, testPrivileges, testPrincipal);
+ superuser.save();
+
+ policies = acMgr.getEffectivePolicies(testRoot);
+ expectedLength = -1; // EXERCISE
+ assertEquals(expectedLength, policies.length);
+
+ policies = acMgr.getEffectivePolicies(childPath);
+ expectedLength = -1; // EXERCISE
+ assertEquals(expectedLength, policies.length);
+
+ setupPolicy(childPath, testPrivileges, testPrincipal);
+ superuser.save();
+
+ policies = acMgr.getEffectivePolicies(childPath);
+ expectedLength = -1; // EXERCISE
+ assertEquals(expectedLength, policies.length);
+ }
+
+ public void testGetEffectivePoliciesAtNodeTypeRoot() throws Exception {
+ AccessControlPolicy[] policies = acMgr.getEffectivePolicies(NodeTypeConstants.NODE_TYPES_PATH);
+
+ int expectedLength = -1; // EXERCISE
+ assertEquals(expectedLength, policies.length);
+
+ // EXERCISE : if there are effective policies at this path, what type of policies to do you expect
+ // EXERCISE : verify your expectation with an assertion
+ }
+
+ public void testGetEffectivePoliciesNewPolicy() throws Exception {
+ setupPolicy(testRoot, testPrivileges, testPrincipal);
+
+ // EXERCISE fix the test such that the assert below passes. explain why this is needed.
+
+ AccessControlPolicy[] policies = acMgr.getEffectivePolicies(testRoot);
+ assertEquals(1, policies.length);
+ }
+
+ public void testGetEffectivePoliciesByPrincipal() throws Exception {
+
+ Set<Principal> principalSet = Collections.singleton(testPrincipal);
+ AccessControlPolicy[] policies = acMgr.getEffectivePolicies(principalSet);
+
+ int expectedLength = -1; // EXERCISE
+ assertEquals(expectedLength, policies.length);
+
+ setupPolicy(testRoot, testPrivileges, testPrincipal);
+ setupPolicy(childPath, testPrivileges, testPrincipal);
+
+ expectedLength = -1; // EXERCISE
+ assertEquals(expectedLength, acMgr.getEffectivePolicies(principalSet).length);
+
+ superuser.save();
+
+ expectedLength = -1; // EXERCISE
+ assertEquals(expectedLength, acMgr.getEffectivePolicies(principalSet).length);
+ }
+
+ public void testSessionGetEffectivePolicies() throws Exception {
+ // grant 'testUser' READ + WRITE privileges at the test root
+ setupPolicy(testRoot, testPrivileges, testPrincipal);
+
+ // grant 'testUser' READ + READ_AC privileges at child path
+ Privilege[] privileges = AccessControlUtils.privilegesFromNames(acMgr, Privilege.JCR_READ, Privilege.JCR_READ_ACCESS_CONTROL);
+ setupPolicy(childPath, privileges, testPrincipal);
+ superuser.save();
+
+ testSession = getTestSession();
+ AccessControlManager testAcMgr = testSession.getAccessControlManager();
+
+ AccessControlPolicy[] effective = testAcMgr.getEffectivePolicies(childPath);
+ int expectedLength = -1; // EXERCISE
+ assertEquals(expectedLength, effective.length);
+ }
+
+ public void testSessionGetEffectivePoliciesWithoutPrivilege() throws Exception {
+ // grant 'testUser' READ + WRITE privileges at the test path
+ setupPolicy(testRoot, testPrivileges, testPrincipal);
+ superuser.save();
+
+ testSession = getTestSession();
+ AccessControlManager testAcMgr = testSession.getAccessControlManager();
+
+ List<String> paths = ImmutableList.of(testRoot, NodeTypeConstants.NODE_TYPES_PATH);
+ for (String path : paths) {
+ // EXERCISE : complete or fix the test case
+ AccessControlPolicy[] effectivePolicies = testAcMgr.getEffectivePolicies(path);
+ }
+ }
+
+ public void testSessionGetEffectivePoliciesByPrincipal() throws Exception {
+ Privilege[] privileges = AccessControlUtils.privilegesFromNames(acMgr, Privilege.JCR_READ, Privilege.JCR_READ_ACCESS_CONTROL);
+ setupPolicy(testRoot, privileges, testPrincipal);
+ setupPolicy(childPath, testPrivileges, EveryonePrincipal.getInstance());
+ superuser.save();
+
+ testSession = getTestSession();
+ JackrabbitAccessControlManager testAcMgr = (JackrabbitAccessControlManager) testSession.getAccessControlManager();
+
+ AccessControlPolicy[] effective = testAcMgr.getEffectivePolicies(Collections.singleton(testPrincipal));
+ int expectedLength = -1; // EXERCISE
+ assertEquals(expectedLength, effective.length);
+
+ // EXERCISE : explain the result
+ }
+
+ public void testSessionGetEffectivePoliciesByPrincipalWithoutPrivileges() throws Exception {
+ setupPolicy(testRoot, testPrivileges, testPrincipal);
+ setupPolicy(childPath, testPrivileges, EveryonePrincipal.getInstance());
+ superuser.save();
+
+ testSession = getTestSession();
+ JackrabbitAccessControlManager testAcMgr = (JackrabbitAccessControlManager) testSession.getAccessControlManager();
+
+ AccessControlPolicy[] effective = testAcMgr.getEffectivePolicies(Collections.singleton(testPrincipal));
+ int expectedLength = -1; // EXERCISE
+ assertEquals(expectedLength, effective.length);
+
+ // EXERCISE : explain the result
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L4_EffectivePoliciesTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L5_AccessControlListImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L5_AccessControlListImplTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L5_AccessControlListImplTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L5_AccessControlListImplTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,276 @@
+/*
+ * 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.accesscontrol;
+
+import java.security.Principal;
+import java.util.Collections;
+import java.util.List;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.Privilege;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.JackrabbitWorkspace;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.security.ExerciseUtility;
+import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.test.AbstractJCRTest;
+import org.apache.jackrabbit.test.NotExecutableException;
+
+import static org.junit.Assert.assertArrayEquals;
+
+/**
+ * <pre>
+ * Module: Authorization (Access Control Management)
+ * =============================================================================
+ *
+ * Title: AccessControlList Implementation Details
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * Understand some of the implementation details applied by the default
+ * access control list provided by the Oak access control management.
+ *
+ * Exercises:
+ *
+ * - {@link #testAddEntryTwice()}
+ * Adding the same ACE twice does not work.
+ * Verify the expectation by looking at the ACEs exposed by the list.
+ *
+ * - {@link #testUpdateAndComplementary()}
+ * The default implementation of the JackrabbitAccessControlList interface
+ * performs some optimization upon ACE-addition.
+ * Walk through the setup and complete the test case such that it passes.
+ *
+ * - {@link #testAddEntryWithInvalidPrincipals()}
+ * This tests creates a list of invalid principals for which adding an ACE
+ * will fail.
+ *
+ * Question: Can you explain for each of these principals why?
+ *
+ * - {@link #testAddEntriesWithCustomKnownPrincipal()}
+ * Here we use a custom principal implementation as well but a principal
+ * with the given name is actually known.
+ * Walk through the test and complete it such that it passes.
+ *
+ * - {@link #testAddEntryWithInvalidPrivilege()}
+ * Walk through the test and explain why creating ACE for the given list of
+ * privilege arrays must fail.
+ *
+ * - {@link #testRemoveInvalidEntry()}
+ * Walk through the removal and explain why removing an ACE with the same
+ * characteristics is expected to fail.
+ *
+ *
+ * Additional Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * The JCR specification mandates the that the principal used to create an ACE
+ * is known to the system.
+ *
+ * - Investigate how the Oak repository can be configured such that creating
+ * ACEs with unknown principals would still succeed.
+ *
+ * Question: Can you name the configuration option and list the allowed values? What are the differences?
+ * Question: Can you find other places in the access control management code
+ * base where this is being used?
+ * Question: Can you imagine the use cases for such a different or relaxed behaviour?
+ *
+ *
+ * Related Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * - {@link L6_AccessControlContentTest}
+ *
+ * </pre>
+ */
+public class L5_AccessControlListImplTest extends AbstractJCRTest {
+
+ private AccessControlManager acMgr;
+ private JackrabbitAccessControlList acl;
+
+ private Principal testPrincipal;
+ private Privilege[] testPrivileges;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ acMgr = superuser.getAccessControlManager();
+
+ testPrincipal = ExerciseUtility.createTestGroup(((JackrabbitSession) superuser).getUserManager()).getPrincipal();
+ superuser.save();
+
+ acl = AccessControlUtils.getAccessControlList(superuser, testRoot);
+ if (acl == null) {
+ throw new NotExecutableException();
+ }
+
+ testPrivileges = AccessControlUtils.privilegesFromNames(acMgr, Privilege.JCR_READ, Privilege.JCR_WRITE);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ Authorizable testGroup = ((JackrabbitSession) superuser).getUserManager().getAuthorizable(testPrincipal);
+ if (testGroup != null) {
+ testGroup.remove();
+ superuser.save();
+ }
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ public void testAddEntryTwice() throws Exception {
+ acl.addEntry(testPrincipal, testPrivileges, true, Collections.<String, Value>emptyMap());
+
+ boolean expectedResult = false; // EXERCISE
+ assertEquals(expectedResult, acl.addEntry(testPrincipal, testPrivileges, true, Collections.<String, Value>emptyMap()));
+
+ // EXERCISE : verify the size of the ACL.
+ }
+
+ public void testUpdateAndComplementary() throws Exception {
+ Privilege[] readPriv = AccessControlUtils.privilegesFromNames(acMgr, Privilege.JCR_READ);
+ Privilege[] writePriv = AccessControlUtils.privilegesFromNames(acMgr, Privilege.JCR_WRITE);
+ Privilege[] acReadPriv = AccessControlUtils.privilegesFromNames(acMgr, Privilege.JCR_READ_ACCESS_CONTROL);
+
+ assertTrue(acl.addEntry(testPrincipal, readPriv, true));
+ assertTrue(acl.addEntry(testPrincipal, writePriv, true));
+ assertTrue(acl.addEntry(testPrincipal, acReadPriv, true));
+
+ int expectedSize = -1; // EXERCISE
+ assertEquals(expectedSize, acl.size());
+
+ assertTrue(acl.addEntry(testPrincipal, readPriv, false));
+
+ expectedSize = -1; // EXERCISE
+ assertEquals(expectedSize, acl.size());
+
+
+ AccessControlEntry[] entries = acl.getAccessControlEntries();
+
+ Privilege[] expectedPrivileges = null; // EXERCISE
+ assertArrayEquals(expectedPrivileges, entries[0].getPrivileges());
+
+ Privilege[] expectedPrivileges1 = null; // EXERCISE
+ assertArrayEquals(expectedPrivileges1, entries[1].getPrivileges());
+ }
+
+ public void testAddEntryWithInvalidPrincipals() throws Exception {
+ // EXERCISE: explain for each principal in the list why using it for an ACE fails
+ List<Principal> invalidPrincipals = ImmutableList.of(
+ new InvalidTestPrincipal("unknown"),
+ null,
+ new PrincipalImpl(""), new Principal() {
+ @Override
+ public String getName() {
+ return "unknown";
+ }
+ });
+
+ for (Principal principal : invalidPrincipals) {
+ try {
+ acl.addAccessControlEntry(principal, testPrivileges);
+ fail("Adding an ACE with an invalid principal should fail");
+ } catch (AccessControlException e) {
+ // success
+ }
+ }
+ }
+
+ public void testAddEntriesWithCustomKnownPrincipal() throws Exception {
+ Principal oakPrincipal = new PrincipalImpl(testPrincipal.getName());
+ Principal principal = new Principal() {
+ @Override
+ public String getName() {
+ return testPrincipal.getName();
+ }
+ };
+
+ assertTrue(acl.addAccessControlEntry(oakPrincipal, AccessControlUtils.privilegesFromNames(acMgr, Privilege.JCR_READ)));
+ assertTrue(acl.addAccessControlEntry(principal, AccessControlUtils.privilegesFromNames(acMgr, Privilege.JCR_READ_ACCESS_CONTROL)));
+
+ int expectedLength = -1; // EXERCISE
+ assertEquals(expectedLength, acl.getAccessControlEntries().length);
+ }
+
+ public void testAddEntryWithInvalidPrivilege() throws Exception {
+ String privilegeName = "AccessControlListImplTestPrivilege";
+ Privilege customPriv = ((JackrabbitWorkspace) superuser.getWorkspace()).getPrivilegeManager().registerPrivilege(privilegeName, true, new String[0]);
+
+ // EXERCISE : walks through this test and explain why adding those ACEs fails.
+ List<Privilege[]> invalidPrivileges = ImmutableList.of(
+ new Privilege[0],
+ null,
+ new Privilege[] {customPriv}
+ );
+
+ for (Privilege[] privs : invalidPrivileges) {
+ try {
+ acl.addAccessControlEntry(testPrincipal, privs);
+ fail("Adding an ACE with invalid privilege array should fail.");
+ } catch (AccessControlException e) {
+ // success
+ }
+ }
+ }
+
+ public void testRemoveInvalidEntry() throws RepositoryException {
+ assertTrue(AccessControlUtils.addAccessControlEntry(superuser, testRoot, testPrincipal, testPrivileges, true));
+
+ // EXERCISE : walk through the removal and explain the expected behaviour.
+ try {
+ acl.removeAccessControlEntry(new JackrabbitAccessControlEntry() {
+ public boolean isAllow() {
+ return false;
+ }
+
+ public String[] getRestrictionNames() {
+ return new String[0];
+ }
+
+ public Value getRestriction(String restrictionName) {
+ return null;
+ }
+
+ public Value[] getRestrictions(String restrictionName) {
+ return null;
+ }
+
+ public Principal getPrincipal() {
+ return testPrincipal;
+ }
+
+ public Privilege[] getPrivileges() {
+ return testPrivileges;
+ }
+ });
+ fail("Passing an unknown ACE should fail");
+ } catch (AccessControlException e) {
+ // success
+ }
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L5_AccessControlListImplTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L6_AccessControlContentTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L6_AccessControlContentTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L6_AccessControlContentTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L6_AccessControlContentTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,229 @@
+/*
+ * 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.accesscontrol;
+
+import java.security.Principal;
+import javax.jcr.Node;
+import javax.jcr.NodeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.Privilege;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.security.ExerciseUtility;
+import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.test.AbstractJCRTest;
+import org.apache.jackrabbit.test.NotExecutableException;
+
+import static org.junit.Assert.assertArrayEquals;
+
+/**
+ * <pre>
+ * Module: Authorization (Access Control Management)
+ * =============================================================================
+ *
+ * Title: Representation of Access Control Content in the Repository
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * Understand how the default implementation represents access control content
+ * in the repository.
+ *
+ * Exercises:
+ *
+ * - Overview
+ * Look {@code org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd}
+ * and try to identify the built in node types used to store access control
+ * content.
+ *
+ * Question: Can explain the meaning of all types?
+ * Question: Why are most item definitions protected?
+ * Question: Can you identify node types that are not used? Can you explain why?
+ *
+ * - {@link #testAclContent()}
+ * This test case writes an ACL to the repository.
+ * Fix the test such that it retrieves the policy node and verify the expected
+ * nature of this node.
+ *
+ * - {@link #testAceContent()}
+ * This test case writes an ACL with entries to the repository.
+ * Fix the test such that it retrieves the policy node and verify the expected
+ * nature of the access control entry nodes.
+ *
+ * - {@link #testRestrictionContent()}
+ * Same as above but this time you should look at the restrictions and how they
+ * are represented in the content.
+ *
+ * - {@link #testMixins()}
+ * Fix the test by defining the expected mixin types.
+ *
+ * Question: Can you explain why those mixins are present and who added them?
+ * Question: Can make a recommendation for other developers wrt the ac-related mixin types? Should they be added manually?
+ *
+ * - {@link #testRepoPolicy()}
+ * Same as {@link #testAclContent()} but this time for the 'null' path.
+ * Fix the test case and verify your expections.
+ *
+ *
+ * Additional Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * - Named {@code ReadPolicy}
+ * In the previous exercises you learned about the special named policy
+ * {@link org.apache.jackrabbit.oak.security.authorization.accesscontrol.AccessControlManagerImpl.ReadPolicy}.
+ *
+ * Question: Can you find the content representation of this policy?
+ * Question: Can you explain what is happening?
+ *
+ * </pre>
+ */
+public class L6_AccessControlContentTest extends AbstractJCRTest {
+
+ private AccessControlManager acMgr;
+ private JackrabbitAccessControlList acl;
+
+ private Principal testPrincipal;
+ private Privilege[] testPrivileges;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ acMgr = superuser.getAccessControlManager();
+
+ testPrincipal = ExerciseUtility.createTestGroup(((JackrabbitSession) superuser).getUserManager()).getPrincipal();
+ superuser.save();
+
+ acl = AccessControlUtils.getAccessControlList(superuser, testRoot);
+ if (acl == null) {
+ throw new NotExecutableException();
+ }
+
+ testPrivileges = AccessControlUtils.privilegesFromNames(acMgr, Privilege.JCR_READ, Privilege.JCR_WRITE);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ Authorizable testGroup = ((JackrabbitSession) superuser).getUserManager().getAuthorizable(testPrincipal);
+ if (testGroup != null) {
+ testGroup.remove();
+ superuser.save();
+ }
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ public void testAclContent() throws RepositoryException {
+ acMgr.setPolicy(testRoot, acl);
+
+ // EXERCISE retrieve the policy node and verify the expected name, primary type and child items
+ String policyPath = null;
+ Node aclNode = superuser.getNode(policyPath);
+
+ String expectedName = null;
+ assertEquals(expectedName, aclNode.getName());
+
+ String expectedPrimaryTypeName = null;
+ assertEquals(expectedPrimaryTypeName, aclNode.getPrimaryNodeType().getName());
+
+ NodeIterator aclChildren = aclNode.getNodes();
+ // EXERCISE verify the correct number + expected nature of the children.
+ }
+
+ public void testAceContent() throws RepositoryException {
+ acl.addAccessControlEntry(testPrincipal, testPrivileges);
+ acl.addEntry(EveryonePrincipal.getInstance(), testPrivileges, false);
+ acMgr.setPolicy(testRoot, acl);
+
+ String policyPath = null; // EXERCISE
+ Node aclNode = superuser.getNode(policyPath);
+
+ NodeIterator aclChildren = aclNode.getNodes();
+
+ int expectedSize = -1; // EXERCISE
+ assertEquals(expectedSize, aclChildren.getSize());
+
+ String expectedPrimaryTypeName = null; // EXERCISE: define the type of the first child node.
+ while (aclChildren.hasNext()) {
+ Node ace = aclChildren.nextNode();
+
+ assertEquals(expectedPrimaryTypeName, ace.getPrimaryNodeType().getName());
+ expectedPrimaryTypeName = null; // EXERCISE: define the type of the next item.
+ }
+
+ Node ace = aclNode.getNodes().nextNode();
+ // EXERCISE: retrieve all mandatory ac-related properties of this node and verify the expected value.
+ }
+
+ public void testRestrictionContent() throws RepositoryException {
+ ValueFactory vf = superuser.getValueFactory();
+ acl.addEntry(testPrincipal, testPrivileges, false,
+ ImmutableMap.of(AccessControlConstants.REP_GLOB, vf.createValue("")),
+ ImmutableMap.of(AccessControlConstants.REP_PREFIXES, new Value[] {vf.createValue("jcr"), vf.createValue("mix")}));
+ acMgr.setPolicy(testRoot, acl);
+
+ String policyPath = null; // EXERCISE
+ Node aclNode = superuser.getNode(policyPath);
+
+ Node ace = aclNode.getNodes().nextNode();
+ // EXERCISE: retrieve the restrictions defined for the single ACE node
+ // EXERCISE: verify the expected properties and their value(s)
+ }
+
+ public void testMixins() throws RepositoryException {
+ acMgr.setPolicy(testRoot, acl);
+
+ NodeType[] mixins = superuser.getNode(acl.getPath()).getMixinNodeTypes();
+ NodeType[] expectedMixins = null;
+ assertArrayEquals(expectedMixins, mixins);
+ }
+
+ public void testRepoPolicy() throws RepositoryException {
+ AccessControlList repoAcl = AccessControlUtils.getAccessControlList(acMgr, null);
+
+ assertNotNull(repoAcl);
+ repoAcl.addAccessControlEntry(testPrincipal, AccessControlUtils.privilegesFromNames(acMgr, PrivilegeConstants.JCR_NAMESPACE_MANAGEMENT));
+ acMgr.setPolicy(null, repoAcl);
+
+ // EXERCISE retrieve the policy node and verify the expected name, primary type and child items
+ String policyPath = null;
+ Node aclNode = superuser.getNode(policyPath);
+
+ String expectedName = null;
+ assertEquals(expectedName, aclNode.getName());
+
+ String expectedPrimaryTypeName = null;
+ assertEquals(expectedPrimaryTypeName, aclNode.getPrimaryNodeType().getName());
+
+ NodeIterator aclChildren = aclNode.getNodes();
+ // EXERCISE verify the correct number + expected nature of the children.
+
+ // EXERCISE: can you also identify which mixins are being involved and where they got applied?
+ }
+}
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L6_AccessControlContentTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L7_RestrictionsTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L7_RestrictionsTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L7_RestrictionsTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L7_RestrictionsTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,197 @@
+/*
+ * 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.accesscontrol;
+
+import java.security.Principal;
+import java.util.Map;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.Privilege;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.security.ExerciseUtility;
+import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+import org.apache.jackrabbit.test.AbstractJCRTest;
+import org.apache.jackrabbit.test.NotExecutableException;
+
+/**
+ * <pre>
+ * Module: Authorization (Access Control Management)
+ * =============================================================================
+ *
+ * Title: Restrictions and Restriction Management
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * Become familiar with the concept of additional restrictions added to a given
+ * access control entry and the API to read and write them.
+ *
+ * For simplicity this test make use of the default restrictions provided by Oak.
+ * Be aware that these are not built-in constants as additional restrictions
+ * are pluggable at runtime. See the advanced exercises.
+ *
+ * Exercises:
+ *
+ * - {@link #testApplicableRestrictions()}
+ * This test uses Jackrabbit API methods to obtain the applicable restrictions.
+ * Complete the test such that you also now the required type of the
+ * restrictions.
+ *
+ * Question: Can you determine from the Jackrabbit API if the restriction is multivalued?
+ *
+ * - {@link #testAddEntryWithRestrictions()}
+ * Create an new ACE with a single valued restriction like e.g. the path globbing
+ * restriction.
+ *
+ * - {@link #testAddEntryWithMultipleRestrictions()}
+ * Create an new ACE with multiple restrictions mixing both single and multi-
+ * valued restrictions.
+ *
+ * - {@link #testRetrieveRestrictionsFromACE()}
+ * This test creates an ACE with restrictions. Complete the test by verifying
+ * your expectations wrt restrictions present on the ACE.
+ *
+ *
+ * Advanced Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * While the restriction API provided by Jackrabbit API is rather limited the
+ * Oak internal way to handle, store and read these restictions is a bit
+ * more elaborate.
+ *
+ * Use the Oak code base and the documentation at
+ * http://jackrabbit.apache.org/oak/docs/security/accesscontrol/restriction.html
+ * to complete the following additional exercises.
+ *
+ * - Take a look at the interfaces and classes defined in
+ * {@code org.apache.jackrabbit.oak.spi.security.authorization.restriction}
+ *
+ * - Investigate how you could plug your custom restriction provider and try
+ * to implement it according to the instructions on the Oak.
+ * Use the stub at {@link org.apache.jackrabbit.oak.security.authorization.restriction.CustomRestrictionProvider}
+ * to complete this exercise.
+ *
+ * - Make your custom restriction provider an OSGi service and deploy it in a
+ * OSGi-base repository setup like Sling (Granite|CQ). Use a low-level
+ * repository browser tool (or a test) to create ACEs making use of the custom
+ * restrictions you decided to implement.
+ *
+ * </pre>
+ *
+ * @see <a href="http://jackrabbit.apache.org/oak/docs/security/accesscontrol/restriction.html">Restriction Management Documentation</a>
+ */
+public class L7_RestrictionsTest extends AbstractJCRTest {
+
+
+ private AccessControlManager acMgr;
+ private JackrabbitAccessControlList acl;
+
+ private Principal testPrincipal;
+ private Privilege[] testPrivileges;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ acMgr = superuser.getAccessControlManager();
+
+ testPrincipal = ExerciseUtility.createTestGroup(((JackrabbitSession) superuser).getUserManager()).getPrincipal();
+ superuser.save();
+
+ acl = AccessControlUtils.getAccessControlList(superuser, testRoot);
+ if (acl == null) {
+ throw new NotExecutableException();
+ }
+
+ testPrivileges = AccessControlUtils.privilegesFromNames(acMgr, Privilege.JCR_READ, Privilege.JCR_WRITE);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ Authorizable testGroup = ((JackrabbitSession) superuser).getUserManager().getAuthorizable(testPrincipal);
+ if (testGroup != null) {
+ testGroup.remove();
+ superuser.save();
+ }
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ public void testApplicableRestrictions() throws RepositoryException {
+ String[] restrictionNames = acl.getRestrictionNames();
+
+ for (String name : restrictionNames) {
+ int type = acl.getRestrictionType(name);
+ int expectedType = PropertyType.UNDEFINED;
+
+ if (AccessControlConstants.REP_GLOB.equals(name)) {
+ expectedType = PropertyType.UNDEFINED; // EXERCISE
+ } else if (AccessControlConstants.REP_NT_NAMES.equals(name)) {
+ expectedType = PropertyType.UNDEFINED; // EXERCISE
+ } else if (AccessControlConstants.REP_PREFIXES.equals(name)) {
+ expectedType = PropertyType.UNDEFINED; // EXERCISE
+ }
+ assertEquals(expectedType, type);
+ }
+ }
+
+ public void testAddEntryWithRestrictions() throws RepositoryException {
+ // EXERCISE : create the restriction map containing a globbing pattern.
+ Map<String, Value> restrictions = null;
+
+ assertTrue(acl.addEntry(testPrincipal, testPrivileges, false, restrictions));
+ }
+
+ public void testAddEntryWithMultiValuedRestriction() throws RepositoryException {
+ // EXERCISE : create the restriction map containing a globbing pattern.
+ Map<String, Value> restrictions = null;
+
+ // EXERCISE : create a map with the multi-valued restrictions as well.
+ Map<String, Value[]> mvRestrictions = null;
+
+ assertTrue(acl.addEntry(testPrincipal, testPrivileges, false, restrictions, mvRestrictions));
+ }
+
+ public void testRetrieveRestrictionsFromACE() throws RepositoryException {
+ ValueFactory vf = superuser.getValueFactory();
+
+ acl.addEntry(testPrincipal, testPrivileges, false,
+ ImmutableMap.of(AccessControlConstants.REP_GLOB, vf.createValue("/*")),
+ ImmutableMap.of(AccessControlConstants.REP_PREFIXES, new Value[] {vf.createValue("jcr"), vf.createValue("rep")})
+ );
+
+ for (AccessControlEntry ace : acl.getAccessControlEntries()) {
+ if (ace instanceof JackrabbitAccessControlEntry) {
+ JackrabbitAccessControlEntry jace = (JackrabbitAccessControlEntry) ace;
+
+ // EXERCISE retrieve the restriction names present on the ace and verify your expectations.
+ // EXERCISE retrieve the restriction values for each restriction and verify your expectations.
+ }
+ }
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L7_RestrictionsTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L8_GlobRestrictionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L8_GlobRestrictionTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L8_GlobRestrictionTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L8_GlobRestrictionTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,51 @@
+/*
+ * 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.accesscontrol;
+
+import org.apache.jackrabbit.oak.AbstractSecurityTest;
+
+/**
+ * <pre>
+ * Module: Authorization (Access Control Management)
+ * =============================================================================
+ *
+ * Title: The Globbing Restriction
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * After having completed this exercises you should be familiar with the rep:glob
+ * restriction as present in the default implementation and able to use it to
+ * limit the effect of a given ACE to a given subtree.
+ *
+ * Exercises:
+ *
+ * - {@link #TODO}
+ *
+ *
+ * Additional Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * TODO
+ *
+ * </pre>
+ *
+ * @see org.apache.jackrabbit.oak.security.authorization.restriction.GlobPattern
+ */
+public class L8_GlobRestrictionTest extends AbstractSecurityTest {
+
+
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/accesscontrol/L8_GlobRestrictionTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/L1_IntroductionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/L1_IntroductionTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/L1_IntroductionTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/L1_IntroductionTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,259 @@
+/*
+ * 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 java.security.Principal;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.jcr.security.AccessControlManager;
+
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+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.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.junit.Test;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * <pre>
+ * Module: Authorization (Permission Evaluation)
+ * =============================================================================
+ *
+ * Title: Introduction
+ * -----------------------------------------------------------------------------
+ *
+ * Become familiar with the way to verify permissions using JCR API.
+ * Get a basic understanding how permission evaluation is used and exposed in Oak
+ * and finally gain insight into some details of the default implementation.
+ *
+ * Exercises:
+ *
+ * - Overview and Usages of Permission Evaluation
+ * Search and list for permission lated methods in the JCR API and recap what
+ * the specification states about permissions compared to access control
+ * management.
+ *
+ * Question: What are the areas in JCR that deal with permissions?
+ * Question: Who is the expected API consumer?
+ * Question: Can you elaborate when it actually makes sense to use this API?
+ * Question: Can you think about potential drawbacks of doing so?
+ *
+ * - Permission Evaluation in Oak
+ * In a second step try to become more familiar with the nature of the
+ * permission evaluation in Oak.
+ *
+ * Question: What is the nature of the public SPI?
+ * Question: Can you identify the main entry point for permission evaluation?
+ * Question: Can you identify to exact location(s) in Oak where read-access is being enforced?
+ * Question: Can you identify the exact location(s) in Oak where all kind of write access is being enforced?
+ *
+ * - Configuration
+ * Look at the default implementation(s) of the {@link org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration}
+ * and try to identify the configurable parts with respect to permission evaluation.
+ * Compare your results with the Oak documentation.
+ *
+ * Question: Can you provide a list of configuration options for the permission evaluation?
+ * Question: Can you identify where these configuration options are being evaluated?
+ * Question: Which options also affect the access control management?
+ *
+ * - Pluggability
+ * Become familar with the pluggable parts of the permission evaluation
+ *
+ * Question: What means does Oak provide to change or extend the permission evaluation?
+ * Question: Can you identify the interfaces that you needed to implement?
+ * Question: Would it be possible to only replace the implementation of {@link org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider}?
+ * How could you achieve this?
+ * And what would be the consequences for the whole authorization module?
+ *
+ *
+ * Advanced Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * - Read Permission Walkthrough
+ * Use {@link #testReadPermissionWalkThrough()} to become familiar with the
+ * very internals of the permission evaluation. Walk through the item read
+ * methods (for simplicity reduced to oak-core only) and be aware of
+ * permission-evaluation related parts.
+ *
+ * Question: Can you list the relevant steps wrt permission evalution?
+ * Question: What is the nature of the returned tree objects?
+ * Question: How can you verify if the editing test session can actually read those trees without using the permission-evalution code?
+ * Question: How can you verify if the properties are accessible.
+ *
+ * - Write Permission Walkthrough
+ * Use {@link #testWritePermissionWalkThrough()} to become familiar with the
+ * internals of the permission evaluation with respect to writing. Walk through
+ * the item write methods (for simplicity reduced to oak-core only) and the
+ * subsequent {@link org.apache.jackrabbit.oak.api.Root#commit()} and be aware
+ * of permission-evaluation related parts.
+ *
+ * Question: Can you list the relevant steps wrt permission evalution?
+ * Question: What can you say about write permissions for special (protected) items?
+ *
+ * - Extending {@link #testReadPermissionWalkThrough()} and {@link #testWritePermissionWalkThrough()}
+ * Use the two test-cases and play with additional access/writes and or
+ * additional (more complex) permission setup.
+ *
+ *
+ * Related Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * - {@link org.apache.jackrabbit.oak.security.authorization.permission.L2_PermissionDiscoveryTest}
+ *
+ * </pre>
+ */
+public class L1_IntroductionTest extends AbstractSecurityTest {
+
+ private ContentSession testSession;
+
+ @Override
+ public void before() throws Exception {
+ super.before();
+ testSession = createTestSession();
+
+ Principal testPrincipal = getTestUser().getPrincipal();
+
+ NodeUtil rootNode = new NodeUtil(root.getTree("/"));
+ NodeUtil a = rootNode.addChild("a", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ a.setString("aProp", "aValue");
+
+ NodeUtil b = a.addChild("b", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ b.setString("bProp", "bValue");
+ // sibling
+ NodeUtil bb = a.addChild("bb", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ bb.setString("bbProp", "bbValue");
+
+ NodeUtil c = b.addChild("c", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ c.setString("cProp", "cValue");
+
+ setupPermission(root, "/a", testPrincipal, true, PrivilegeConstants.JCR_READ);
+ setupPermission(root, "/a/b", testPrincipal, true, PrivilegeConstants.JCR_ADD_CHILD_NODES);
+ setupPermission(root, "/a/bb", testPrincipal, false, PrivilegeConstants.REP_READ_PROPERTIES);
+ setupPermission(root, "/a/b/c", testPrincipal, true, PrivilegeConstants.REP_ADD_PROPERTIES);
+
+ root.commit();
+ }
+
+ @Override
+ public void after() throws Exception {
+ try {
+ if (testSession != null) {
+ testSession.close();
+ }
+ root.getTree("/a").remove();
+ root.commit();
+ } finally {
+ super.after();
+ }
+ }
+
+ /**
+ * Setup simple allow/deny permissions (without restrictions).
+ *
+ * @param root The editing root.
+ * @param path The path of the access controlled tree.
+ * @param principal The principal for which new ACE is being created.
+ * @param isAllow {@code true} if privileges are granted; {@code false} otherwise.
+ * @param privilegeNames The privilege names.
+ * @throws Exception If an error occurs.
+ */
+ private void setupPermission(@Nonnull Root root,
+ @Nullable String path,
+ @Nonnull Principal principal,
+ boolean isAllow,
+ @Nonnull String... privilegeNames) throws Exception {
+ AccessControlManager acMgr = getAccessControlManager(root);
+ JackrabbitAccessControlList acl = checkNotNull(AccessControlUtils.getAccessControlList(acMgr, path));
+ acl.addEntry(principal, AccessControlUtils.privilegesFromNames(acMgr, privilegeNames), isAllow);
+ acMgr.setPolicy(path, acl);
+ root.commit();
+ }
+
+ @Test
+ public void testReadPermissionWalkThrough() {
+ Root testRoot = testSession.getLatestRoot();
+
+ // EXERCISE verify if these tree are accessible using Tree#exists()
+ // Question: can you explain why using Tree.exists is sufficient and you don't necessarily need to perform the check on the PermissionProvider?
+ Tree rootTree = testRoot.getTree("/");
+ Tree bTree = testRoot.getTree("/a/b");
+ Tree cTree = testRoot.getTree("/a/b/c");
+
+ // EXERCISE verify if this is an accessible property? Q: how can you do this withouth testing the readability on the PermissionProvider?
+ PropertyState bProp = bTree.getProperty("bProp");
+ PropertyState bbProp = testRoot.getTree("/a/bb").getProperty("bbProp");
+ PropertyState cProp = cTree.getProperty("cProp");
+ }
+
+ @Test
+ public void testWritePermissionWalkThrough() throws CommitFailedException {
+ Root testRoot = testSession.getLatestRoot();
+
+ // EXERCISE walk through the test and fix it such that it passes.
+
+ Tree bTree = testRoot.getTree("/a/b");
+
+ // add a new child node at '/a/b' and persist the change to trigger the permission evaluation.
+ // EXERCISE: does it work with the current permission setup? if not, why (+ add exception handling)?
+ try {
+ Tree child = bTree.addChild("childName");
+ child.setProperty(JcrConstants.JCR_PRIMARYTYPE, NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ testRoot.commit();
+ } finally {
+ testRoot.refresh();
+ }
+
+ // now change the primary type of the 'bTree'
+ // EXERCISE: does it work with the current permission setup? if not, why (+ add exception handling)?
+ try {
+ bTree.setProperty(JcrConstants.JCR_PRIMARYTYPE, JcrConstants.NT_UNSTRUCTURED);
+ testRoot.commit();
+ } finally {
+ testRoot.refresh();
+ }
+
+ Tree cTree = testRoot.getTree("/a/b/c");
+
+ // now change the regula property 'cProp' of the 'cTree'
+ // EXERCISE: does it work with the current permission setup? if not, why (+ add exception handling)?
+ try {
+ cTree.setProperty("cProp", "changedValue");
+ testRoot.commit();
+ } finally {
+ testRoot.refresh();
+ }
+
+
+ // finally we try to add a new property to the 'cTree'
+ // EXERCISE: does it work with the current permission setup? if not, why (+ add exception handling)?
+ try {
+ cTree.setProperty("anotherCProp", "val");
+ testRoot.commit();
+ } finally {
+ root.refresh();
+ }
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/L1_IntroductionTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/L2_PermissionDiscoveryTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/L2_PermissionDiscoveryTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/L2_PermissionDiscoveryTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/L2_PermissionDiscoveryTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,317 @@
+/*
+ * 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 java.security.Principal;
+import java.util.Map;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.Privilege;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.security.ExerciseUtility;
+import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.test.AbstractJCRTest;
+import org.apache.jackrabbit.test.NotExecutableException;
+
+/**
+ * <pre>
+ * Module: Authorization (Permission Evaluation)
+ * =============================================================================
+ *
+ * Title: PermissionDiscoveryTest
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * Become familiar with the permission discovery as provided by {@link javax.jcr.Session}.
+ *
+ * Exercises:
+ *
+ * - Overview
+ * Look at {@link javax.jcr.Session} and list the action constants that may
+ * be used to test permissions of the editing session.
+ * Compare this list with the built-in privileges defined in {@link javax.jcr.security.Privilege}
+ * and explain the discrepancy.
+ *
+ * Question: Can you find out with the predefined actions if you can lock an existing node?
+ * Question: Can you find out with the predefined actions if you can register a new namespace?
+ *
+ * - {@link #testReadAccess()}
+ * While there exists {@link javax.jcr.Session#ACTION_READ}, you can equally
+ * use the direct methods to test for existance of a given item.
+ * Use the test-case to learn about the difference and when using
+ * {@link Session#hasPermission(String, String)} could actually make sense.
+ *
+ * - {@link #testModifyPermissions()}
+ * Test illustrating the usage of {@link Session#ACTION_SET_PROPERTY}. Fill
+ * in the expected values and explain why.
+ *
+ * Question: How is {@link Session#ACTION_SET_PROPERTY} mapped to the internal permissions?
+ * Question: Can make a table illustrating the effect of the individual permissions
+ * (granted/denied) on the result depending on whether the item exists or not?
+ *
+ * - {@link #testRemovePermissions()}
+ * Test illustrating the usage of {@link Session#ACTION_REMOVE}. Fill
+ * in the expected values and explain why.
+ *
+ * Question: How is {@link Session#ACTION_REMOVE} mapped to the internal permissions?
+ * Question: Can make a table illustrating the effect of the individual permissions
+ * (granted/denied) on the result depending on whether the item exists or not?
+ * Question: Discuss what is special about the removal of nodes when
+ * comparing the action, the privileges and the internal permissions
+ *
+ * - {@link #testAddPermissions()}
+ * Test illustrating the usage of {@link Session#ACTION_ADD_NODE} and {@link Session#ACTION_SET_PROPERTY}
+ * if used to create a new non-existing property. Fill in the expected values and explain why.
+ *
+ * Question: How is {@link Session#ACTION_ADD_NODE} mapped to the internal permissions?
+ * Question: Can make a table illustrating the effect of the individual permissions
+ * (granted/denied) on the result depending on whether the item exists or not?
+ * Question: Discuss what is special about the creation of new nodes when
+ * comparing the action, the privileges and the internal permissions
+ *
+ * - {@link #testOakPermissions()}
+ * The default permission implementation in Oak also allows for passing
+ * string representation of the permission constants as 'actions'.
+ * Adjust the test such that it passes.
+ *
+ *
+ * Additional Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * - Session.checkPermission
+ * Apart from {@link javax.jcr.Session#hasPermission(String, String)} there also
+ * exists {@link javax.jcr.Session#checkPermission(String, String)}.
+ *
+ * Question: Can you explain why it is generally recommended to use the non-throwing variant?
+ *
+ * - Explict vs. Builtin Permission Test
+ *
+ * Question: Discuss why it is generally preferrable to leave the permission
+ * evaluation to the repository instead of doing this manually in the application?
+ * Question: Can you identify use-cases where this is nevertheless required?
+ * How could they be avoided?
+ *
+ * </pre>
+ *
+ * @see javax.jcr.Session#hasPermission(String, String)
+ * @see javax.jcr.Session#checkPermission(String, String)
+ */
+public class L2_PermissionDiscoveryTest extends AbstractJCRTest {
+
+ private Principal testPrincipal;
+ private Session testSession;
+
+ private String childPath;
+ private String propertyPath;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ Property p = testRootNode.setProperty(propertyName1, "val");
+ propertyPath = p.getPath();
+
+ Node child = testRootNode.addNode(nodeName1);
+ childPath = child.getPath();
+
+ User testUser = ExerciseUtility.createTestUser(((JackrabbitSession) superuser).getUserManager());
+ testPrincipal = testUser.getPrincipal();
+
+ Privilege[] privs = AccessControlUtils.privilegesFromNames(superuser, Privilege.JCR_READ, PrivilegeConstants.REP_ADD_PROPERTIES);
+ Privilege[] privs2 = AccessControlUtils.privilegesFromNames(superuser, Privilege.JCR_ADD_CHILD_NODES);
+ if (!AccessControlUtils.addAccessControlEntry(superuser, testRoot, testPrincipal, privs, true) ||
+ !AccessControlUtils.addAccessControlEntry(superuser, childPath, testPrincipal, privs2, true)) {
+ throw new NotExecutableException();
+ }
+
+ superuser.save();
+ testSession = superuser.getRepository().login(ExerciseUtility.getTestCredentials(testUser.getID()));
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ if (testSession != null && testSession.isLive()) {
+ testSession.logout();
+ }
+ Authorizable testUser = ((JackrabbitSession) superuser).getUserManager().getAuthorizable(testPrincipal);
+ if (testUser != null) {
+ testUser.remove();
+ superuser.save();
+ }
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ private static Boolean[] existsAndHasPermission(Boolean expectedExists, Boolean expectedHasPermission) {
+ return new Boolean[] {expectedExists, expectedHasPermission};
+ }
+
+ public void testReadAccess() throws RepositoryException {
+ // EXERCISE: fill in the expected values
+ Map<String, Boolean[]> nodeTests = ImmutableMap.of(
+ "/", existsAndHasPermission(null, null),
+ testRoot, existsAndHasPermission(null, null),
+ childPath, existsAndHasPermission(null, null),
+ childPath + "/new", existsAndHasPermission(null, null)
+ );
+
+ for (String nodePath : nodeTests.keySet()) {
+ Boolean[] expected = nodeTests.get(nodePath);
+
+ assertEquals(expected[0].booleanValue(), testSession.nodeExists(nodePath));
+ assertEquals(expected[1].booleanValue(), testSession.hasPermission(nodePath, Session.ACTION_READ));
+ }
+
+ // EXERCISE: fill in the expected values
+ Map<String, Boolean[]> propertyTests = ImmutableMap.of(
+ "/jcr:primaryType", existsAndHasPermission(null, null),
+ propertyPath, existsAndHasPermission(null, null),
+ childPath + "/new", existsAndHasPermission(null, null)
+ );
+
+ for (String pPath : propertyTests.keySet()) {
+ Boolean[] expected = propertyTests.get(pPath);
+
+ assertEquals(expected[0].booleanValue(), testSession.nodeExists(pPath));
+ assertEquals(expected[1].booleanValue(), testSession.hasPermission(pPath, Session.ACTION_READ));
+ }
+ }
+
+ public void testModifyPermissions() throws RepositoryException {
+ // EXERCISE: fill in the expected values
+ Map<String, Boolean> modifyPropertyTests = ImmutableMap.of(
+ "/jcr:primaryType", null,
+ testRoot, null,
+ propertyPath, null
+ );
+ for (String pPath : modifyPropertyTests.keySet()) {
+ boolean canModifyProperty = modifyPropertyTests.get(pPath);
+ assertEquals(canModifyProperty, testSession.hasPermission(pPath, Session.ACTION_SET_PROPERTY));
+ }
+ }
+
+ public void testRemovePermissions() throws RepositoryException {
+ // EXERCISE: fill in the expected values
+ Map<String, Boolean> removePropertyTests = ImmutableMap.of(
+ "/jcr:primaryType", null,
+ propertyPath, null,
+ childPath + "/new", null
+ );
+ for (String pPath : removePropertyTests.keySet()) {
+ boolean canRemoveProperty = removePropertyTests.get(pPath);
+ assertEquals(canRemoveProperty, testSession.hasPermission(pPath, Session.ACTION_REMOVE));
+ }
+
+ // EXERCISE: fill in the expected values
+ Map<String, Boolean> removeNodesTests = ImmutableMap.of(
+ "/", null,
+ testRoot, null,
+ childPath, null,
+ childPath + "/new", null
+ );
+ for (String nodePath : removeNodesTests.keySet()) {
+ boolean canRemoveNode = removeNodesTests.get(nodePath);
+ assertEquals(canRemoveNode, testSession.hasPermission(nodePath, Session.ACTION_REMOVE));
+ }
+
+
+ // EXERCISE : change the permission setup such that the following tests succeed.
+ testSession.refresh(false);
+ assertTrue(testSession.hasPermission(childPath, Session.ACTION_REMOVE));
+ testSession.getNode(childPath).remove();
+ testSession.save();
+
+ // EXERCISE : change the permission setup such that the following tests succeed.
+
+ testSession.refresh(false);
+ assertTrue(testSession.hasPermission(propertyPath, Session.ACTION_REMOVE));
+ testSession.getProperty(propertyPath).remove();
+ testSession.save();
+
+ }
+
+ public void testAddPermissions() throws RepositoryException {
+ // EXERCISE: fill in the expected values
+ Map<String, Boolean> addPropertyTests = ImmutableMap.of(
+ "/propertyName1", null,
+ testRoot, null,
+ propertyPath, null,
+ childPath + "/new", null
+ );
+ for (String pPath : addPropertyTests.keySet()) {
+ boolean canAddProperty = addPropertyTests.get(pPath);
+ assertEquals(canAddProperty, testSession.hasPermission(pPath, Session.ACTION_SET_PROPERTY));
+ }
+
+ // EXERCISE: fill in the expected values
+ Map<String, Boolean> addNodesTests = ImmutableMap.of(
+ "/childNode", null,
+ testRoot, null,
+ testRoot + "/new", null,
+ childPath, null,
+ childPath + "/new", null
+ );
+ for (String childPath : addNodesTests.keySet()) {
+ boolean canAddNode = addNodesTests.get(childPath);
+ assertEquals(canAddNode, testSession.hasPermission(childPath, Session.ACTION_ADD_NODE));
+ }
+
+ // EXERCISE : change the permission setup such that the following tests succeed.
+
+ testSession.refresh(false);
+ testSession.getNode(testRoot).addNode(nodeName2);
+ testSession.save();
+ }
+
+ public void testOakPermissions() throws RepositoryException {
+ String modifyPropertyPermissions = null; // EXERCISE:
+ assertFalse(testSession.hasPermission(propertyPath, modifyPropertyPermissions));
+
+ // EXERCISE : modify the permission setup such that the following tests pass
+
+ testSession.refresh(false);
+ assertTrue(testSession.hasPermission(propertyPath, modifyPropertyPermissions));
+ assertFalse(testSession.hasPermission(propertyPath, Permissions.getString(Permissions.REMOVE_PROPERTY|Permissions.ADD_PROPERTY)));
+
+ String addItemPermissions = null; // EXERCISE
+ assertTrue(testSession.hasPermission(childPath, addItemPermissions));
+
+ String permissions = null; // EXERCISE
+ assertFalse(testSession.hasPermission(childPath, permissions));
+
+ // EXERCISE : modify the permission setup such that the following tests pass
+ assertFalse(testSession.hasPermission(testRoot, permissions));
+ assertTrue(testSession.hasPermission(childPath, permissions));
+
+ Node cNode = testSession.getNode(childPath);
+ cNode.addMixin(mixVersionable);
+ testSession.save();
+ cNode.checkin();
+ cNode.checkout();
+ }
+
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/L2_PermissionDiscoveryTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/L3_PrecedenceRulesTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/L3_PrecedenceRulesTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/L3_PrecedenceRulesTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/authorization/permission/L3_PrecedenceRulesTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,262 @@
+/*
+ * 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 java.security.Principal;
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.Privilege;
+
+import org.apache.jackrabbit.api.JackrabbitSession;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.security.ExerciseUtility;
+import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.test.AbstractJCRTest;
+
+/**
+ * <pre>
+ * Module: Authorization (Permission Evaluation)
+ * =============================================================================
+ *
+ * Title: Basic Precedence Rules in Permission Evaluation
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * The aim of this exercise is to make you familiar with some implementations
+ * details of the default permission evaluation.
+ *
+ * Exercises:
+ *
+ * - Overview
+ * Read the on the Oak documentation about the default permission evaluation
+ * implementation such that the following test cases are easy to solve.
+ *
+ *
+ * - {@link #testGroupMembership()}
+ * Test illustrating that permissions granted/denied to groups are inherited
+ * to the group members.
+ *
+ * - {@link #testHierarchy()}
+ * Test illustrating that in the default implemenation permissions are inherited
+ * though the item hierarchy.
+ * Create the correct permission setup to verify this.
+ *
+ * - {@link #testAceOrder()}
+ * This case shows how the order of ACEs within a given ACL affect the resulting
+ * permissions. Fix the test case without dropping either of the two ACEs such
+ * that the test passes and look at the ACEs present on the list before and
+ * after the fix.
+ *
+ * Question: How many ways to you find to fix the test?
+ *
+ * - {@link #testPrecedenceOfUserPrincipals()}
+ * The goal of this test is to make you aware of the precendence of user principals
+ * during permission evaluation.
+ * Fix the test according to the instructions.
+ *
+ * Question: How many ways to you find to fix the test?
+ *
+ * - {@link #testCombination()} and {@link #testCombination2()}
+ * Additional tests combining the different rules testes above.
+ * Fill in the correct values and explain the behaviour.
+ *
+ *
+ * Additional Exercise
+ * -----------------------------------------------------------------------------
+ *
+ * So far the test-cases only modify read permissions.
+ *
+ * - Write additional test-cases playing with different privileges
+ *
+ * - Once you feel comfortable with the basics include restrictions in your
+ * tests and verify your expectations.
+ *
+ * - Create a test setting up permission at the 'null' path and describe the
+ * result.
+ * Question: What can you say about the inheritance rules you learned so far
+ * when it comes to repository level permissions?
+ *
+ * HINT: there are plenty of test-cases present with oak-jcr and oak-core. Use
+ * the tests already present to invent new exercises.
+ *
+ *
+ * </pre>
+ *
+ * @see <a href="http://jackrabbit.apache.org/oak/docs/security/permission/evaluation.html">Permission Evaluation in the Oak Docu</a>
+ */
+public class L3_PrecedenceRulesTest extends AbstractJCRTest {
+
+ private Principal testPrincipal;
+ private Principal testGroupPrincipal;
+ private Session testSession;
+
+ private String childPath;
+ private String propertyPath;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ Property p = testRootNode.setProperty(propertyName1, "val");
+ propertyPath = p.getPath();
+
+ Node child = testRootNode.addNode(nodeName1);
+ childPath = child.getPath();
+
+ User testUser = ExerciseUtility.createTestUser(((JackrabbitSession) superuser).getUserManager());
+ Group testGroup = ExerciseUtility.createTestGroup(((JackrabbitSession) superuser).getUserManager());
+ testGroup.addMember(testUser);
+ superuser.save();
+
+ testPrincipal = testUser.getPrincipal();
+ testGroupPrincipal = testGroup.getPrincipal();
+
+ AccessControlUtils.addAccessControlEntry(superuser, testRoot, EveryonePrincipal.getInstance(), AccessControlUtils.privilegesFromNames(superuser, Privilege.JCR_ALL), false);
+
+ testSession = superuser.getRepository().login(ExerciseUtility.getTestCredentials(testUser.getID()));
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ if (testSession != null && testSession.isLive()) {
+ testSession.logout();
+ }
+ UserManager uMgr = ((JackrabbitSession) superuser).getUserManager();
+ Authorizable testUser = uMgr.getAuthorizable(testPrincipal);
+ if (testUser != null) {
+ testUser.remove();
+ }
+ Authorizable testGroup = uMgr.getAuthorizable(testGroupPrincipal);
+ if (testGroup != null) {
+ testGroup.remove();
+ }
+ superuser.save();
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ public void testGroupMembership() throws RepositoryException {
+ assertFalse(testSession.nodeExists(testRoot));
+
+ assertTrue(((java.security.acl.Group) testGroupPrincipal).isMember(testPrincipal));
+
+ AccessControlUtils.addAccessControlEntry(superuser, testRoot, testGroupPrincipal, AccessControlUtils.privilegesFromNames(superuser, Privilege.JCR_READ), true);
+ superuser.save();
+
+ testSession.refresh(false);
+ boolean expected = false; // EXERCISE
+ assertEquals(expected, testSession.nodeExists(testRoot));
+ }
+
+ public void testHierarchy() throws RepositoryException {
+ assertFalse(testSession.nodeExists(testRoot));
+ assertFalse(testSession.nodeExists(childPath));
+ assertFalse(testSession.propertyExists(propertyPath));
+
+ Principal principal = testPrincipal;
+ // EXERCISE : create the correct permission setup such that the test session can read all items below.
+ // EXERCISE : how many entries do you need to create?
+ superuser.save();
+
+ testSession.refresh(false);
+ assertTrue(testSession.nodeExists(testRoot));
+ assertTrue(testSession.nodeExists(childPath));
+ assertTrue(testSession.propertyExists(propertyPath));
+ }
+
+ public void testAceOrder() throws RepositoryException {
+ assertFalse(testSession.nodeExists(testRoot));
+
+ Privilege[] readPrivs = AccessControlUtils.privilegesFromNames(superuser, Privilege.JCR_READ);
+
+ // EXERCISE: fix the permission setup such that the test success without dropping either ACE
+ JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(superuser, testRoot);
+ acl.addEntry(testGroupPrincipal, readPrivs, true);
+ acl.addEntry(EveryonePrincipal.getInstance(), readPrivs, false);
+ superuser.getAccessControlManager().setPolicy(acl.getPath(), acl);
+ superuser.save();
+
+ testSession.refresh(false);
+ assertTrue(testSession.nodeExists(testRoot));
+ assertTrue(testSession.propertyExists(propertyPath));
+
+ }
+
+ public void testPrecedenceOfUserPrincipals() throws RepositoryException {
+ Privilege[] readPrivs = AccessControlUtils.privilegesFromNames(superuser, Privilege.JCR_READ);
+
+ JackrabbitAccessControlList acl = AccessControlUtils.getAccessControlList(superuser, testRoot);
+ acl.addEntry(testPrincipal, readPrivs, false);
+ acl.addEntry(testGroupPrincipal, readPrivs, true);
+ superuser.getAccessControlManager().setPolicy(acl.getPath(), acl);
+ superuser.save();
+
+ // EXERCISE what is the expected result?
+ testSession.refresh(false);
+ Boolean canRead = null; // EXERCISE
+ assertEquals(canRead.booleanValue(), testSession.nodeExists(testRoot));
+ assertEquals(canRead.booleanValue(), testSession.nodeExists(childPath));
+
+ // EXERCISE: now change the permission setup such that the testSession has read access
+ // EXERCISE: how many ways to you find to achieve this?
+ }
+
+ public void testCombination() throws RepositoryException {
+ Privilege[] readPrivs = AccessControlUtils.privilegesFromNames(superuser, Privilege.JCR_READ);
+
+ AccessControlUtils.addAccessControlEntry(superuser, testRoot, testPrincipal, readPrivs, false);
+ AccessControlUtils.addAccessControlEntry(superuser, childPath, testGroupPrincipal, readPrivs, true);
+ superuser.save();
+
+ // EXERCISE what is the expected result?
+ testSession.refresh(false);
+ Boolean canRead = null; // EXERCISE
+ assertEquals(canRead.booleanValue(), testSession.nodeExists(testRoot));
+ assertEquals(canRead.booleanValue(), testSession.propertyExists(propertyPath));
+ assertEquals(canRead.booleanValue(), testSession.nodeExists(childPath));
+ }
+
+ public void testCombination2() throws RepositoryException {
+ Privilege[] readPrivs = AccessControlUtils.privilegesFromNames(superuser, Privilege.JCR_READ);
+
+ AccessControlUtils.addAccessControlEntry(superuser, testRoot, testPrincipal, readPrivs, false);
+ AccessControlUtils.addAccessControlEntry(superuser, testRoot, testPrincipal, new String[] {PrivilegeConstants.REP_READ_PROPERTIES}, true);
+ AccessControlUtils.addAccessControlEntry(superuser, childPath, testGroupPrincipal, readPrivs, false);
+ superuser.save();
+
+ // EXERCISE what is the expected result?
+ testSession.refresh(false);
+ Boolean canRead = null; // EXERCISE
+ assertEquals(canRead.booleanValue(), testSession.nodeExists(testRoot));
+ canRead = null; // EXERCISE
+ assertEquals(canRead.booleanValue(), testSession.propertyExists(propertyPath));
+ canRead = null; // EXERCISE
+ assertEquals(canRead.booleanValue(), testSession.nodeExists(childPath));
+ canRead = null; // EXERCISE
+ assertEquals(canRead.booleanValue(), testSession.propertyExists(childPath+"/jcr:primaryType"));
+ }
+}
\ No newline at end of file