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 2018/04/19 15:22:47 UTC
svn commit: r1829562 [2/2] - in /jackrabbit/oak/trunk/oak-exercise/src:
main/java/org/apache/jackrabbit/oak/exercise/security/authorization/models/predefined/
main/java/org/apache/jackrabbit/oak/exercise/security/authorization/models/readonly/
main/jav...
Copied: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/advanced/L4_CustomAccessControlManagementTest.java (from r1829512, jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/advanced/L5_CustomAccessControlManagementTest.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/advanced/L4_CustomAccessControlManagementTest.java?p2=jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/advanced/L4_CustomAccessControlManagementTest.java&p1=jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/advanced/L5_CustomAccessControlManagementTest.java&r1=1829512&r2=1829562&rev=1829562&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/advanced/L5_CustomAccessControlManagementTest.java (original)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/advanced/L4_CustomAccessControlManagementTest.java Thu Apr 19 15:22:47 2018
@@ -16,6 +16,58 @@
*/
package org.apache.jackrabbit.oak.exercise.security.authorization.advanced;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.security.Principal;
+import java.util.Map;
+import javax.annotation.Nonnull;
+import javax.jcr.ImportUUIDBehavior;
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.Session;
+import javax.jcr.nodetype.NodeDefinition;
+import javax.jcr.nodetype.PropertyDefinition;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.AccessControlPolicyIterator;
+import javax.jcr.security.NamedAccessControlPolicy;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+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.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.exercise.security.authorization.models.simplifiedroles.ThreeRolesAuthorizationConfiguration;
+import org.apache.jackrabbit.oak.exercise.security.authorization.models.simplifiedroles.ThreeRolesConstants;
+import org.apache.jackrabbit.oak.exercise.security.principal.CustomPrincipalConfiguration;
+import org.apache.jackrabbit.oak.jcr.Jcr;
+import org.apache.jackrabbit.oak.jcr.repository.RepositoryImpl;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.nodetype.ReadOnlyNodeTypeManager;
+import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
+import org.apache.jackrabbit.oak.security.authorization.composite.CompositeAuthorizationConfiguration;
+import org.apache.jackrabbit.oak.security.internal.SecurityProviderHelper;
+import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
+import org.apache.jackrabbit.oak.spi.security.authorization.AuthorizationConfiguration;
+import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.PolicyOwner;
+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.principal.EveryonePrincipal;
+import org.apache.jackrabbit.oak.spi.security.principal.PrincipalConfiguration;
+import org.apache.jackrabbit.oak.spi.whiteboard.DefaultWhiteboard;
+import org.apache.jackrabbit.oak.spi.xml.ProtectedNodeImporter;
+import org.junit.Test;
+
+import static junit.framework.TestCase.assertEquals;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
/**
* <pre>
* Module: Advanced Authorization Topics
@@ -25,14 +77,449 @@ package org.apache.jackrabbit.oak.exerci
* -----------------------------------------------------------------------------
*
* Goal:
- * TODO
+ * Learn how to write your own access control management and how to properly
+ * secure access control content.
+ * The exercises is this lesson will make use of a authorization model stub that
+ * already has the permission evaluation implemented. The entry point of that model
+ * is {@link ThreeRolesAuthorizationConfiguration}.
*
* Exercises:
- * TODO
+ *
+ * - {@link #testGetPolicies()}
+ * Complete the implementation of {@link AccessControlManager#getPolicies(String)}
+ * such that the test passes.
+ * Adjust the number of expected policies and the type of policies according
+ * to your implementation.
+ *
+ * Questions:
+ * - what type of policy do you want to expose?
+ * - does any of the existing types of access control policies fit your needs?
+ * existing types include
+ * > {@link NamedAccessControlPolicy},
+ * > {@link javax.jcr.security.AccessControlList},
+ * > {@link org.apache.jackrabbit.api.security.JackrabbitAccessControlList},
+ * > {@link org.apache.jackrabbit.api.security.authorization.PrincipalSetPolicy}
+ * - if you choose to define your own policy type: what does it look like?
+ * - should {@link AccessControlManager#getPolicies(String)} return one or many policies?
+ *
+ * - {@link #testGetEffectivePolicies()}
+ * Complete the implementation of {@link AccessControlManager#getEffectivePolicies(String)}
+ * such that the test passes.
+ * NOTE: computation of effective policies is specified to be a best-effort operation.
+ *
+ * Questions:
+ * - what type of policy do you want to expose?
+ * - what are the effective policies for those nodes that don't have the custom
+ * policy set? or in other words: which nodes are affected by the policy set
+ * at /test/a in the test setup?
+ * - does the set of effective policies include any default policies that have
+ * not been explicit set?
+ * - what's the maximal number of effective policies your implementation may return?
+ *
+ * - {@link #testGetApplicablePolicies()}
+ * Complete the implementation of {@link AccessControlManager#testGetApplicablePolicies(String)}
+ * such that the test passes.
+ *
+ * Questions:
+ * - what type of policies do you expose here?
+ * - are they they same as with {@link #testGetPolicies()} and/or {@link #testGetEffectivePolicies()}?
+ * - does /test/a still have applicable policies?
+ * - what about the path outside of the tree defined by 'supportedPath' configuration option?
+ * - as you learned in the previous section and can see in {@link org.apache.jackrabbit.oak.exercise.security.authorization.models.simplifiedroles.ThreeRolesPermissionProvider}
+ * this simplified authorization model doesn't respect nesting of policies in a
+ * given tree. what does that mean for the applicable policies?
+ * - what's the maximal number of applicable policies your implementation may return at a given path?
+ *
+ * - {@link #testSetPolicy()}
+ * Implement {@link AccessControlManager#setPolicy(String, AccessControlPolicy)} and
+ * {@link PolicyOwner#defines(String, AccessControlPolicy)} such that policies
+ * can be written to the repository in a composite authorization setup.
+ * The {@link PolicyOwner} is also required for the subsequent tests.
+ *
+ * - {@link #testSetModifiedPolicy()}
+ * Modify the custom access control setup at /test/a such that the principal
+ * associated with the test-user get moved from the editor to the owner set.
+ *
+ * - {@link #testRemovePolicy()}
+ * Implement {@link AccessControlManager#removePolicy(String, AccessControlPolicy)} such
+ * that the test passes.
+ *
+ * - {@link #testAccessControlContentIsProtected()}
+ * Your authorization setup should come with some validation of the access control
+ * content written to the repository.
+ * Write a {@link org.apache.jackrabbit.oak.spi.commit.ValidatorProvider} and
+ * plug it into the authorization configuration such that the test-case passes
+ * and discuss each of the assertions made.
+ *
+ * Questions:
+ * - Can you identify possible shortcomings with the 4 validation steps proposed?
+ * - Under which circumstances could any of them might not be desirable?
+ *
+ * - {@link #testAccessControlItemsAreProtectedByNodeTypeDefinition()}
+ * Identify the code in the simplifiedroles authorization model that makes sure
+ * the simple policy node and it's properties have JCR item definitions that are
+ * protected.
+ *
+ * Discuss why this is needed and what the effect of this measure is.
+ * Complete the test case by
+ * - testing the protected status of access control content using JCR API calls.
+ * - verifying the protected status using JCR write API
+ *
+ * Question:
+ * - Can you identify which parts of Oak are responsible for enforcing the protected status?
+ *
+ * - {@link #testImportNodeWithPolicy}
+ * This is a follow-up on {@link #testAccessControlItemsAreProtectedByNodeTypeDefinition()} as
+ * the protected item definitions are not only enforced upon regular write
+ * operations but also when calling {@link javax.jcr.Session#importXML(String, InputStream, int)},
+ * {@link javax.jcr.Workspace#importXML(String, InputStream, int)} and related calls.
+ *
+ * Fix the simplifiedroles authorization model such that the test passes.
+ * Hint: you need to implement a custom implementation of {@link ProtectedNodeImporter}
+ * and ensure the {@link AuthorizationConfiguration#getProtectedItemImporters()}
+ * exposes it to the security setup.
+ *
+ * - {@link #testImportNodeWithPolicyAndUnknownPrincipal}
+ * Variant of {@link #testImportNodeWithPolicy} that attempts to import a policy
+ * referring to an {@code Principal} that is not known to any of the providers.
+ *
+ * Questions:
+ * - What do you need to do to the setup and possibly your importer code such
+ * that importing unknown principals is allowed?
+ * - In case your importer didn't check the validity of the principals:
+ * Discuss the adjustments you would need to make to your importer in order
+ * to enforce the different levels of validation check.
+ *
+ *
+ * Advanced Exercise
+ * -----------------------------------------------------------------------------
+ *
+ * The AccessControlManager stub doesn't implement {@link org.apache.jackrabbit.api.security.JackrabbitAccessControlManager}.
+ * Take a look at the additional methods defined by the extension in Jackrabbit API.
+ *
+ * As you can see the extra methods all related to access control management by
+ * {@link Principal}.
+ *
+ * Questions:
+ * - Would it be possible/sensible to have your implementation additionally implement
+ * the methods {@link org.apache.jackrabbit.api.security.JackrabbitAccessControlManager}?
+ *
+ * - If you think it's possible, what would the implementation look like?
+ *
+ * - Can you spot any obstacles with that approach?
+ *
+ *
+ * Related Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * - {@link L5_CustomPermissionEvaluationTest}
*
* </pre>
*/
-public class L5_CustomAccessControlManagementTest {
+public class L4_CustomAccessControlManagementTest extends AbstractSecurityTest {
+
+ @Override
+ protected SecurityProvider initSecurityProvider() {
+ ThreeRolesAuthorizationConfiguration threeRolesAuthorizationConfiguration = new ThreeRolesAuthorizationConfiguration();
+ threeRolesAuthorizationConfiguration.setParameters(ConfigurationParameters.of("supportedPath", "/test"));
+
+ CustomPrincipalConfiguration pc = new CustomPrincipalConfiguration();
+ pc.setParameters(ConfigurationParameters.of("knownPrincipals", new String[] {"principalR", "principalE", "principalO"}));
+
+ SecurityProvider sp = super.initSecurityProvider();
+ SecurityProviderHelper.updateConfig(sp, threeRolesAuthorizationConfiguration, AuthorizationConfiguration.class);
+ SecurityProviderHelper.updateConfig(sp, pc, PrincipalConfiguration.class);
+
+ return sp;
+ }
+
+ @Override
+ protected ConfigurationParameters getSecurityConfigParameters() {
+ return ConfigurationParameters.of("authorizationCompositionType", CompositeAuthorizationConfiguration.CompositionType.OR.toString());
+ }
+
+ @Override
+ public void before() throws Exception {
+ super.before();
+
+ Tree testTree = TreeUtil.addChild(root.getTree("/"), "test", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ Tree aTree = TreeUtil.addChild(testTree, "a", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ aTree.setProperty("aProp", "value");
+
+ Tree abTree = TreeUtil.addChild(aTree, "b", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ abTree.setProperty("abProp", "value");
+
+
+ TreeUtil.addMixin(aTree, ThreeRolesConstants.MIX_REP_THREE_ROLES_POLICY, root.getTree(NodeTypeConstants.NODE_TYPES_PATH), null);
+ Tree rolePolicy = TreeUtil.addChild(aTree, ThreeRolesConstants.REP_3_ROLES_POLICY, ThreeRolesConstants.NT_REP_THREE_ROLES_POLICY);
+ rolePolicy.setProperty(ThreeRolesConstants.REP_READERS, ImmutableSet.of("principalR", EveryonePrincipal.NAME), Type.STRINGS);
+ rolePolicy.setProperty(ThreeRolesConstants.REP_EDITORS, ImmutableSet.of("principalE",getTestUser().getPrincipal().getName()), Type.STRINGS);
+ rolePolicy.setProperty(ThreeRolesConstants.REP_OWNERS, ImmutableSet.of("principalO"), Type.STRINGS);
+
+ // add one node outside the scope of the supported path
+ Tree outside = TreeUtil.addChild(root.getTree("/"), "outside", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+
+ root.commit();
+
+ // to verify that setup with CompositeAuthorizationConfiguration.CompositionType.OR
+ // uncomment the lines below
+ /*
+ try (ContentSession cs = createTestSession()) {
+ Root r = createTestSession().getLatestRoot();
+ assertTrue(r.getTree("/test/a").exists());
+ }
+ */
+ }
+
+ private AccessControlManager getAcManager(@Nonnull Root root) {
+ return getConfig(AuthorizationConfiguration.class).getAccessControlManager(root, NamePathMapper.DEFAULT);
+ }
+
+ private Repository buildJcrRepository() {
+ return new RepositoryImpl(
+ getContentRepository(),
+ new DefaultWhiteboard(),
+ getSecurityProvider(),
+ Jcr.DEFAULT_OBSERVATION_QUEUE_LENGTH,
+ null,
+ false);
+ }
+
+
+ /**
+ * EXERCISE: complete {@link AccessControlManager#getPolicies(String)} such that
+ * the policy that has been 'manually' created in the setup is properly exposed
+ * by the access control management API.
+ */
+ @Test
+ public void testGetPolicies() throws Exception {
+ AccessControlPolicy[] policies = getAcManager(root).getPolicies("/test/a");
+
+ int len = -1; // EXERCISE: set expected length. 1 is the minimum but there might be more.
+ assertEquals(len, policies.length);
+
+ // EXERCISE: additionally assert that the policies is of the type you defined
+ for (int i = 0; i < len; i++) {
+ assertTrue(policies[i] instanceof AccessControlPolicy); // EXERCISE: replace by type chosen!
+ }
+ }
+
+ @Test
+ public void testGetEffectivePolicies() throws Exception {
+ // EXERCISE: set expected number of effective policies for all paths in the map.
+ Map<String,Integer> m = ImmutableMap.of("/", -1, "/test", -1, "/test/a/b", -1, "/outside", -1);
+
+ for (String path : m.keySet()) {
+ AccessControlPolicy[] policies = getAcManager(root).getEffectivePolicies(path);
+
+ int len = m.get(path); // EXERCISE: set expected length. 1 is the minimum but there might be more.
+ assertEquals(len, policies.length);
+
+ // EXERCISE: additionally assert that the policies is of the type you defined
+ for (int i = 0; i < len; i++) {
+ assertTrue(policies[i] instanceof AccessControlPolicy); // EXERCISE: replace by type chosen!
+ }
+ }
+ }
+
+ @Test
+ public void testGetApplicablePolicies() throws Exception {
+ // EXERCISE: set expected number of applicable policies for all paths in the map.
+ Map<String,Integer> m = ImmutableMap.of("/test/a", -1, "/test/a/b", -1, "/outside", -1);
+
+ for (String path : m.keySet()) {
+ AccessControlPolicyIterator it = getAcManager(root).getApplicablePolicies(path);
+ assertEquals(m.get(path).longValue(), it.getSize());
+
+ // EXERCISE: additionally assert that the policies is of the type you defined
+ while (it.hasNext()) {
+ assertTrue(it.nextAccessControlPolicy() instanceof AccessControlPolicy); // EXERCISE: replace by type chosen!
+ }
+ }
+ }
+
+ @Test
+ public void testSetPolicy() throws Exception {
+ Tree t = TreeUtil.addChild(root.getTree("/test"), "another", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ AccessControlManager acMgr = getAcManager(root);
+ AccessControlPolicy[] policies = acMgr.getPolicies(t.getPath());
+
+ // EXERCISE: set your custom policy/policies at /test/another such that
+ // the following assertions pass.
+ // ... write your code here
+
+ root.commit();
+
+ PrincipalManager pm = getPrincipalManager(root);
+ Map<Principal,Long> m = ImmutableMap.of(
+ getTestUser().getPrincipal(), Permissions.NO_PERMISSION,
+ pm.getEveryone(), Permissions.NO_PERMISSION,
+ pm.getPrincipal("principalR"), Permissions.READ,
+ pm.getPrincipal("principalE"), Permissions.NO_PERMISSION,
+ pm.getPrincipal("principalO"), ThreeRolesConstants.SUPPORTED_PERMISSIONS
+ );
+ for (Principal principal : m.keySet()) {
+ PermissionProvider pp = getConfig(AuthorizationConfiguration.class).getPermissionProvider(root, adminSession.getWorkspaceName(), ImmutableSet.of(principal));
+ assertTrue(pp.isGranted(t, null, m.get(principal)));
+ }
+ }
+
+ @Test
+ public void testSetModifiedPolicy() throws Exception {
+ AccessControlManager acMgr = getAcManager(root);
+ AccessControlPolicy[] policies = acMgr.getPolicies("/test/a");
+
+ // EXERCISE: modify policies such that the testuser principal becomes owner instead of editor
+ // ... write your code here
+
+ for (AccessControlPolicy policy : policies) {
+ acMgr.setPolicy("/test/a", policy);
+ }
+ root.commit();
+
+ try (ContentSession cs = createTestSession()) {
+ Root r = createTestSession().getLatestRoot();
+ PermissionProvider pp = getConfig(AuthorizationConfiguration.class).getPermissionProvider(r, cs.getWorkspaceName(), cs.getAuthInfo().getPrincipals());
+ assertTrue(pp.isGranted("/test/a", Permissions.getString(ThreeRolesConstants.SUPPORTED_PERMISSIONS)));
+ }
+ }
+
+ @Test
+ public void testRemovePolicy() throws Exception {
+ AccessControlManager acMgr = getAcManager(root);
+ for (AccessControlPolicy policy : acMgr.getPolicies("/test/a")) {
+ acMgr.removePolicy("/test/a", policy);
+ }
+ root.commit();
+ assertEquals(0, acMgr.getPolicies("/test/a").length);
+
+ }
+
+ @Test
+ public void testAccessControlContentIsProtected() throws Exception {
+ Tree test = root.getTree("/test");
+
+ try {
+ Tree missingMixin = TreeUtil.addChild(test, ThreeRolesConstants.REP_3_ROLES_POLICY, ThreeRolesConstants.NT_REP_THREE_ROLES_POLICY);
+ root.commit();
+ fail("Adding policy without mixin must fail.");
+ } catch (CommitFailedException e) {
+ // success
+ }
+
+ try {
+ test.setProperty(ThreeRolesConstants.REP_OWNERS, 437);
+ root.commit();
+ fail("Using name of protected policy property outside of the context of a policy must fail.");
+ } catch (CommitFailedException e) {
+ // success
+ }
+
+ try {
+ Tree b = root.getTree("/test/a/b");
+ TreeUtil.addMixin(b, ThreeRolesConstants.MIX_REP_THREE_ROLES_POLICY, root.getTree(NodeTypeConstants.NODE_TYPES_PATH), null);
+ Tree nestedPolicy = TreeUtil.addChild(b, ThreeRolesConstants.REP_3_ROLES_POLICY, ThreeRolesConstants.NT_REP_THREE_ROLES_POLICY);
+ root.commit();
+
+ fail("Creation of nested three-roles-policy must fail (NOTE: this is an arbitrary limitation for the sake of simplifying permission evaluation).");
+ } catch (CommitFailedException e) {
+ // success
+ }
+
+ try {
+ Tree outside = root.getTree("/outside");
+ TreeUtil.addMixin(outside, ThreeRolesConstants.MIX_REP_THREE_ROLES_POLICY, root.getTree(NodeTypeConstants.NODE_TYPES_PATH), null);
+ Tree nestedPolicy = TreeUtil.addChild(outside, ThreeRolesConstants.REP_3_ROLES_POLICY, ThreeRolesConstants.NT_REP_THREE_ROLES_POLICY);
+ root.commit();
+
+ fail("Creation of nested three-roles-policy outside of the configured supported path must fail.");
+ } catch (CommitFailedException e) {
+ // success
+ }
+
+ }
+
+ @Test
+ public void testAccessControlItemsAreProtectedByNodeTypeDefinition() throws Exception {
+ ReadOnlyNodeTypeManager ntMgr = ReadOnlyNodeTypeManager.getInstance(root, NamePathMapper.DEFAULT);
+
+ Tree aTree = root.getTree("/test/a");
+ Tree policyTree = aTree.getChild(ThreeRolesConstants.REP_3_ROLES_POLICY);
+
+ NodeDefinition policyDef = ntMgr.getDefinition(aTree, policyTree);
+ assertTrue(policyDef.isProtected());
+
+ for (String propName : new String[] {ThreeRolesConstants.REP_READERS, ThreeRolesConstants.REP_EDITORS, ThreeRolesConstants.REP_OWNERS}) {
+ PropertyDefinition propDef = ntMgr.getDefinition(policyTree, policyTree.getProperty(propName), true);
+ assertTrue(propDef.isProtected());
+ }
+
+ Repository jcrRepository = buildJcrRepository();
+
+ // EXERCISE: test protected status of items using JCR API calls
+ // EXERCISE: verify that the protected status of the access control content is enforced
+ // ... write your code here
+ }
+
+ @Test
+ public void testImportNodeWithPolicy() throws Exception {
+ Repository jcrRepository = new RepositoryImpl(
+ getContentRepository(),
+ new DefaultWhiteboard(),
+ getSecurityProvider(),
+ Jcr.DEFAULT_OBSERVATION_QUEUE_LENGTH,
+ null,
+ false);
+
+ Session adminSession = jcrRepository.login(getAdminCredentials(), null);
+ try {
+ String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+ "<sv:node sv:name=\"another2\" xmlns:mix=\"http://www.jcp.org/jcr/mix/1.0\" xmlns:nt=\"http://www.jcp.org/jcr/nt/1.0\" xmlns:fn_old=\"http://www.w3.org/2004/10/xpath-functions\" xmlns:fn=\"http://www.w3.org/2005/xpath-functions\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:sv=\"http://www.jcp.org/jcr/sv/1.0\" xmlns:rep=\"internal\" xmlns:jcr=\"http://www.jcp.org/jcr/1.0\">" +
+ "<sv:property sv:name=\"jcr:primaryType\" sv:type=\"Name\"><sv:value>oak:Unstructured</sv:value></sv:property>" +
+ "<sv:property sv:name=\"jcr:mixinTypes\" sv:type=\"Name\"><sv:value>rep:ThreeRolesMixin</sv:value></sv:property>" +
+ "<sv:node sv:name=\"rep:threeRolesPolicy\" " +
+ "<sv:property sv:name=\"jcr:primaryType\" sv:type=\"Name\"><sv:value>rep:ThreeRolesPolicy</sv:value></sv:property>" +
+ "<sv:property sv:name=\"rep:readers\" sv:type=\"String\"><sv:value>principalR</sv:value></sv:property>" +
+ "</sv:node>" +
+ "</sv:node>";
+
+ adminSession.importXML("/test", new ByteArrayInputStream(xml.getBytes()), ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
+
+ Node n = adminSession.getNode("/test/another");
+ AccessControlPolicy[] policies = adminSession.getAccessControlManager().getPolicies("/test/another");
+ assertTrue(policies.length > 0);
+
+ } finally {
+ adminSession.refresh(false);
+ adminSession.logout();
+ }
+ }
+
+ @Test
+ public void testImportNodeWithPolicyAndUnknownPrincipal() throws Exception {
+ Repository jcrRepository = buildJcrRepository();
+
+ Session adminSession = jcrRepository.login(getAdminCredentials(), null);
+ try {
+ String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
+ "<sv:node sv:name=\"another2\" xmlns:mix=\"http://www.jcp.org/jcr/mix/1.0\" xmlns:nt=\"http://www.jcp.org/jcr/nt/1.0\" xmlns:fn_old=\"http://www.w3.org/2004/10/xpath-functions\" xmlns:fn=\"http://www.w3.org/2005/xpath-functions\" xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:sv=\"http://www.jcp.org/jcr/sv/1.0\" xmlns:rep=\"internal\" xmlns:jcr=\"http://www.jcp.org/jcr/1.0\">" +
+ "<sv:property sv:name=\"jcr:primaryType\" sv:type=\"Name\"><sv:value>oak:Unstructured</sv:value></sv:property>" +
+ "<sv:property sv:name=\"jcr:mixinTypes\" sv:type=\"Name\"><sv:value>rep:ThreeRolesMixin</sv:value></sv:property>" +
+ "<sv:node sv:name=\"rep:threeRolesPolicy\" " +
+ "<sv:property sv:name=\"jcr:primaryType\" sv:type=\"Name\"><sv:value>rep:ThreeRolesPolicy</sv:value></sv:property>" +
+ "<sv:property sv:name=\"rep:readers\" sv:type=\"String\"><sv:value>unknownPrincipal</sv:value></sv:property>" +
+ "</sv:node>" +
+ "</sv:node>";
+
+ adminSession.importXML("/test", new ByteArrayInputStream(xml.getBytes()), ImportUUIDBehavior.IMPORT_UUID_COLLISION_THROW);
+ Node n = adminSession.getNode("/test/another");
+ AccessControlPolicy[] policies = adminSession.getAccessControlManager().getPolicies("/test/another");
+ assertTrue(policies.length > 0);
+ } finally {
+ adminSession.refresh(false);
+ adminSession.logout();
+ }
+ }
}
\ No newline at end of file
Copied: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/advanced/L5_CustomPermissionEvaluationTest.java (from r1829512, jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/advanced/L6_CustomPermissionEvaluationTest.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/advanced/L5_CustomPermissionEvaluationTest.java?p2=jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/advanced/L5_CustomPermissionEvaluationTest.java&p1=jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/advanced/L6_CustomPermissionEvaluationTest.java&r1=1829512&r2=1829562&rev=1829562&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/advanced/L6_CustomPermissionEvaluationTest.java (original)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/exercise/security/authorization/advanced/L5_CustomPermissionEvaluationTest.java Thu Apr 19 15:22:47 2018
@@ -16,6 +16,43 @@
*/
package org.apache.jackrabbit.oak.exercise.security.authorization.advanced;
+import java.security.Principal;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.Nonnull;
+import javax.jcr.GuestCredentials;
+import javax.jcr.Session;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+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.commons.PathUtils;
+import org.apache.jackrabbit.oak.exercise.security.authorization.models.predefined.PredefinedAuthorizationConfiguration;
+import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
+import org.apache.jackrabbit.oak.plugins.tree.TreeUtil;
+import org.apache.jackrabbit.oak.security.authentication.AuthenticationConfigurationImpl;
+import org.apache.jackrabbit.oak.security.authentication.token.TokenConfigurationImpl;
+import org.apache.jackrabbit.oak.security.internal.SecurityProviderBuilder;
+import org.apache.jackrabbit.oak.security.principal.PrincipalConfigurationImpl;
+import org.apache.jackrabbit.oak.security.privilege.PrivilegeConfigurationImpl;
+import org.apache.jackrabbit.oak.security.user.UserConfigurationImpl;
+import org.apache.jackrabbit.oak.spi.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
+import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
+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.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.util.Text;
+import org.junit.Test;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
/**
* <pre>
* Module: Advanced Authorization Topics
@@ -25,14 +62,144 @@ package org.apache.jackrabbit.oak.exerci
* -----------------------------------------------------------------------------
*
* Goal:
- * TODO
+ * Write a custom {@link org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionProvider}
+ * for a predefined requirement in order to become familiar with the details of
+ * the Oak permission evaluation.
*
* Exercises:
- * TODO
+ *
+ * Complete the implementation of {@link org.apache.jackrabbit.oak.exercise.security.authorization.models.predefined.PredefinedPermissionProvider}
+ * such that the tests pass.
+ *
+ *
+ * Advanced Exercise
+ * -----------------------------------------------------------------------------
+ *
+ * Currently the {@link org.apache.jackrabbit.oak.exercise.security.authorization.models.predefined.PredefinedPermissionProvider}
+ * doesn't implement {@link org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider} interface
+ * and can therefore not be used in a setup that combines multipe authorization models.
+ *
+ * As an advanced exercise modify the {@link org.apache.jackrabbit.oak.exercise.security.authorization.models.predefined.PredefinedPermissionProvider}
+ * to additionally implement {@link org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider}
+ * and deploy the {@link PredefinedAuthorizationConfiguration} in a setup with
+ * multiple authorization models.
+ *
+ * - Discuss the additional methods defined by {@link org.apache.jackrabbit.oak.spi.security.authorization.permission.AggregatedPermissionProvider}.
+ * - Clarify which type of 'Authorization Composition' your implementation should be used.
+ * - Observe the result of your combination and explain the results to effective permissions.
*
* </pre>
*/
-public class L6_CustomPermissionEvaluationTest {
+public class L5_CustomPermissionEvaluationTest extends AbstractSecurityTest {
+
+ private static final String[] ACTION_NAMES = new String[] {
+ Session.ACTION_READ, Session.ACTION_ADD_NODE, Session.ACTION_SET_PROPERTY, Session.ACTION_REMOVE
+ };
+
+ private List<Tree> trees;
+ private PropertyState prop;
+
+ @Override
+ protected SecurityProvider initSecurityProvider() {
+ AuthorizationConfiguration ac = new PredefinedAuthorizationConfiguration();
+
+ return SecurityProviderBuilder.newBuilder().with(
+ new AuthenticationConfigurationImpl(), ConfigurationParameters.EMPTY,
+ new PrivilegeConfigurationImpl(), ConfigurationParameters.EMPTY,
+ new UserConfigurationImpl(), ConfigurationParameters.EMPTY,
+ ac, ConfigurationParameters.EMPTY,
+ new PrincipalConfigurationImpl(), ConfigurationParameters.EMPTY,
+ new TokenConfigurationImpl(), ConfigurationParameters.EMPTY)
+ .with(getSecurityConfigParameters())
+ .withRootProvider(getRootProvider())
+ .withTreeProvider(getTreeProvider())
+ .build();
+ }
+
+ @Override
+ public void before() throws Exception {
+ super.before();
+
+ prop = PropertyStates.createProperty("prop", "value");
+
+ Tree testTree = TreeUtil.addChild(root.getTree("/"), "contentA", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ Tree aTree = TreeUtil.addChild(testTree, "a", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ aTree.setProperty(prop);
+
+ Tree aaTree = TreeUtil.addChild(aTree, "a", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ aaTree.setProperty(prop);
+
+ Tree bTree = TreeUtil.addChild(root.getTree("/"), "contentB", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ bTree.setProperty(prop);
+
+ Tree bbTree = TreeUtil.addChild(bTree, "b", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ bbTree.setProperty(prop);
+
+ Tree cTree = TreeUtil.addChild(root.getTree("/"), "contentC", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ cTree.setProperty(prop);
+
+ Tree ccTree = TreeUtil.addChild(cTree, "c", NodeTypeConstants.NT_OAK_UNSTRUCTURED);
+ ccTree.setProperty(prop);
+
+ root.commit();
+
+ trees = ImmutableList.<Tree>builder().add(root.getTree("/")).add(testTree).add(aTree).add(aaTree).add(bTree).add(bbTree).add(cTree).add(ccTree).build();
+
+ }
+
+ private PermissionProvider getPermissionProvider(@Nonnull Set<Principal> principals) {
+ return getConfig(AuthorizationConfiguration.class).getPermissionProvider(root, adminSession.getWorkspaceName(), principals);
+ }
+
+ private Iterable<String> getTreePaths() {
+ return Iterables.transform(trees, Tree::getPath);
+ }
+
+ @Test
+ public void testAdministratorHasFullAccessEverywhere() {
+ for (String path : getTreePaths()) {
+ Tree t = root.getTree(path);
+ assertFalse(t.exists());
+ }
+
+ PermissionProvider pp = getPermissionProvider(adminSession.getAuthInfo().getPrincipals());
+ for (Tree t : trees) {
+ pp.getPrivileges(t).contains(PrivilegeConstants.JCR_ALL);
+ assertTrue(pp.isGranted(t, null, Permissions.ALL));
+ assertTrue(pp.isGranted(t, prop, Permissions.ALL));
+
+ String treePath = t.getPath();
+ String allActions = Text.implode(ACTION_NAMES, ",");
+ assertTrue(pp.isGranted(treePath, allActions));
+ assertTrue(pp.isGranted(PathUtils.concat(treePath, prop.getName()), allActions));
+ }
+ }
+
+ @Test
+ public void testGuestHasNowherePermissions() throws Exception {
+ try (ContentSession guest = login(new GuestCredentials())) {
+ Root r = guest.getLatestRoot();
+ for (String path : getTreePaths()) {
+ Tree t = r.getTree(path);
+ assertFalse(t.exists());
+ }
+
+ PermissionProvider pp = getPermissionProvider(guest.getAuthInfo().getPrincipals());
+ for (Tree t : trees) {
+ pp.getPrivileges(t).isEmpty();
+ for (long permission : Permissions.aggregates(Permissions.ALL)) {
+ assertFalse(pp.isGranted(t, null, permission));
+ assertFalse(pp.isGranted(t, prop, permission));
+ }
+ for (String action : ACTION_NAMES) {
+ String treePath = t.getPath();
+ assertFalse(pp.isGranted(treePath, action));
+ assertFalse(pp.isGranted(PathUtils.concat(treePath, prop.getName()), action));
+ }
+ }
+ }
+ }
+ // TODO: add more tests
}
\ No newline at end of file