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 [6/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/user/L3_UserVsPrincipalTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L3_UserVsPrincipalTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L3_UserVsPrincipalTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L3_UserVsPrincipalTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,223 @@
+/*
+ * 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.user;
+
+import java.security.Principal;
+import java.util.Map;
+import java.util.UUID;
+import javax.jcr.RepositoryException;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+
+import com.google.common.collect.ImmutableMap;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+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.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.security.ExerciseUtility;
+import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.apache.jackrabbit.oak.security.ExerciseUtility.TEST_USER_HINT;
+import static org.apache.jackrabbit.oak.security.ExerciseUtility.TEST_GROUP_HINT;
+import static org.apache.jackrabbit.oak.security.ExerciseUtility.TEST_PRINCIPAL_HINT;
+import static org.apache.jackrabbit.oak.security.ExerciseUtility.TEST_GROUP_PRINCIPAL_HINT;
+
+/**
+ * <pre>
+ * Module: User Management | Principal Management
+ * =============================================================================
+ *
+ * Title: User vs. Principal
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * Understand the difference between {@link org.apache.jackrabbit.api.security.user.User}
+ * and {@link java.security.Principal}.
+ *
+ * Exercises:
+ *
+ * - {@link #testLookup()}
+ * Test case illustrating lookup of principals and authorizables by principal
+ * name and ID as well as authorizable lookup by principal.
+ * Fix the test-case and making you familiar with the distiction between
+ * the ID and the principal name in the first place.
+ *
+ * - {@link #testCreateUserWithGroupPrincipalName()}
+ * This test attempts to create a new user with a principal that is already
+ * used by a Group. Complete the test-case such that it passes.
+ *
+ * - {@link #testCreateWithReverse()}
+ * Test case that attempts to create a user using the principal name of another
+ * user as ID and vice versa. Complete|Fix the test and explain the expected
+ * and the actually behavior.
+ *
+ *
+ * Additional Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * - {@link #testLoginWithPrincipalName()}
+ * Test case creating SimpleCredentials from principal name + password and create a
+ * new ContentSession from these credentials. Fix the case and make the
+ * appropriate assertions.
+ *
+ * - {@link #testAccessControlEntryWithId()}
+ * Test case attempting to create a new access control entry for a principal
+ * based from an authorizable ID. Fix the case and make the appropriate assertions.
+ *
+ *
+ * Related Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * - {@link org.apache.jackrabbit.oak.security.authentication.L2_AuthInfoTest}
+ * For tests related to exposure of principal and ID upon successful login.
+ *
+ * - {@link L6_AuthorizableContentTest}
+ * for tests related to the content structure of users/groups and how the
+ * ID and the principal name are represented there.
+ *
+ * </pre>
+ */
+public class L3_UserVsPrincipalTest extends AbstractSecurityTest {
+
+ private String testId = ExerciseUtility.getTestId(TEST_USER_HINT);
+ private Principal testPrincipal = ExerciseUtility.getTestPrincipal(TEST_PRINCIPAL_HINT);
+
+ private String testGroupId = ExerciseUtility.getTestId(TEST_GROUP_HINT);
+ private Principal testGroupPrincipal = ExerciseUtility.getTestPrincipal(TEST_GROUP_PRINCIPAL_HINT);
+
+ private User testUser;
+ private Group testGroup;
+
+ private PrincipalManager principalManager;
+
+ @Override
+ public void before() throws Exception {
+ super.before();
+
+ UserManager userMgr = getUserManager(root);
+ testUser = ExerciseUtility.createTestUser(userMgr);
+ testGroup = userMgr.createGroup(testGroupId, testGroupPrincipal, null);
+
+ testGroup.addMember(testUser);
+ root.commit();
+
+ principalManager = getPrincipalManager(root);
+ }
+
+ @Override
+ public void after() throws Exception {
+ try {
+ testUser.remove();
+ testGroup.remove();
+ root.commit();
+ } finally {
+ super.after();
+ }
+ }
+
+ @Test
+ public void testLookup() throws RepositoryException {
+ Map<String, Object[]> resultMap = ImmutableMap.of(
+ testId, new Object[]{null, null, null},
+ testPrincipal.getName(), new Object[]{null, null, null},
+ testGroupId, new Object[]{null, null},
+ testGroupPrincipal.getName(), new Object[]{null, null}
+ );
+
+ for (String key : resultMap.keySet()) {
+ Object[] result = resultMap.get(key);
+
+ // lookup principal by "ID"
+ Principal expectedP = (Principal) result[0];
+ Principal principal = principalManager.getPrincipal(key);
+ assertEquals(expectedP, principal);
+
+ // lookup authorizable by "principal"
+ Principal p = new PrincipalImpl(key);
+ Authorizable a = getUserManager(root).getAuthorizable(p);
+ if (a != null) {
+ assertEquals(expectedP, a.getPrincipal());
+ }
+
+ // lookup Authorizable by "ID"
+ Authorizable expectedA = (Authorizable) result[1];
+ a = getUserManager(root).getAuthorizable(key);
+ assertEquals(expectedA, a);
+
+ }
+ }
+
+ @Test
+ public void testCreateUserWithGroupPrincipalName() throws RepositoryException, CommitFailedException {
+ // EXERCISE: fix the test-case with the correct assertions and exception catching! And explain why...
+ User user2 = null;
+ try {
+ user2 = getUserManager(root).createUser(UUID.randomUUID().toString(), ExerciseUtility.TEST_PW, testGroupPrincipal, null);
+ root.commit();
+ } finally {
+ if (user2 != null) {
+ user2.remove();
+ root.commit();
+ }
+ }
+ }
+
+ @Test
+ public void testCreateWithReverse() throws RepositoryException, CommitFailedException {
+ // EXERCISE: fix the test-case with the correct assertions and exception catching!
+ // EXERCISE: if creating the user suceeds : verify if the testUser and user2 are equal. explain why!
+ User user2 = null;
+ try {
+ user2 = getUserManager(root).createUser(testPrincipal.getName(), ExerciseUtility.TEST_PW, new PrincipalImpl(testId), null);
+ root.commit();
+
+ Boolean expectedEquals = null; // EXERCISE
+ assertEquals(expectedEquals.booleanValue(), testUser.equals(user2));
+
+ } finally {
+ if (user2 != null) {
+ user2.remove();
+ root.commit();
+ }
+ }
+ }
+
+ @Test
+ public void testLoginWithPrincipalName() throws Exception {
+ // EXERCISE fix the test case and add proper verification
+ login(ExerciseUtility.getTestCredentials(testPrincipal.getName())).close();
+ }
+
+ @Test
+ public void testAccessControlEntryWithId() throws RepositoryException {
+ AccessControlManager acMgr = getAccessControlManager(root);
+
+ // EXERCISE fix the test case
+ String[] ids = new String[] {testId, testGroupId};
+ for (String id : ids) {
+ AccessControlList acl = AccessControlUtils.getAccessControlList(acMgr, "/");
+ acl.addAccessControlEntry(new PrincipalImpl(id), AccessControlUtils.privilegesFromNames(acMgr, PrivilegeConstants.JCR_READ));
+ }
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L3_UserVsPrincipalTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L4_AuthorizableIdTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L4_AuthorizableIdTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L4_AuthorizableIdTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L4_AuthorizableIdTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,163 @@
+/*
+ * 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.user;
+
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.JcrConstants;
+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.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.security.ExerciseUtility;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.apache.jackrabbit.oak.util.TreeUtil;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * <pre>
+ * Module: User Management
+ * =============================================================================
+ *
+ * Title: Authorizable ID
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * Understand what the ID of an authorizable stands for, how it is reflected
+ * in the API. Furthermore this exercises aims to make you familiar with
+ * some implementation details wrt the ID.
+ *
+ * Exercises:
+ *
+ * - {@link #getById()}
+ * Use this test again to become familiar with the authorizable lookup by ID
+ * and the nature of the authorizable ID.
+ *
+ * - {@link #testIdConflict()}
+ * This test illustrates how the user management implementation deals with
+ * conflicting IDs upon user/group creation.
+ * Fix the test without changing the params of the createUser/createGroup calls.
+ *
+ *
+ * Advanced Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * - {@link #testIdWithManualCreation()}
+ * This exercise aims to create a new user manually using the Oak API (which
+ * doesn't apply the checks for protected items).
+ * Use this test to understand how authorizable uniqueness is enforced in the
+ * repository by fixing the test case
+ *
+ * Question: Can you list all properties with a uniqueness constraint enforced upon?
+ * Question: Can you explain how this is enforced and what is the part that defines this uniqueness?
+ *
+ *
+ * Related Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * - {@link L5_UuidTest}
+ *
+ * </pre>
+ *
+ * @see org.apache.jackrabbit.api.security.user.UserManager
+ * @see org.apache.jackrabbit.api.security.user.Authorizable#getID()
+ */
+public class L4_AuthorizableIdTest extends AbstractSecurityTest {
+
+ private User testUser;
+ private Group testGroup;
+
+ @Override
+ public void before() throws Exception {
+ super.before();
+
+ testUser = ExerciseUtility.createTestUser(getUserManager(root));
+ testGroup = ExerciseUtility.createTestGroup(getUserManager(root));
+ root.commit();
+ }
+
+ @Override
+ public void after() throws Exception {
+ try {
+ if (testUser != null) {
+ testUser.remove();
+ }
+ if (testGroup != null) {
+ testGroup.remove();
+ }
+ root.commit();
+ } finally {
+ super.after();
+ }
+ }
+
+ @Test
+ public void testGetByID() throws RepositoryException {
+ // EXERCISE fix the test-case
+ UserManager uMgr = getUserManager(root);
+ Group g = uMgr.getAuthorizable(testUser.getID(), Group.class);
+
+ assertEquals(g, uMgr.getAuthorizable(testGroup.getID()));
+ assertEquals(g, uMgr.getAuthorizable(testGroup.getPrincipal().getName()));
+ }
+
+ @Test
+ public void testIdConflict() throws RepositoryException, CommitFailedException {
+ // EXERCISE: fix this test without changing the ID-parameter of the 2 create-calls.
+
+ User conflictUser = getUserManager(root).createUser(testUser.getID(), null);
+ root.refresh();
+
+ Group conflictGroup = getUserManager(root).createGroup(testUser.getID());
+ root.refresh();
+ }
+
+ @Test
+ public void testIdWithManualCreation() throws RepositoryException, CommitFailedException {
+ Tree userTree = root.getTree(testUser.getPath());
+ Tree authorizableFolder = userTree.getParent();
+
+ // EXERCISE: fix the test
+ try {
+ String id = TreeUtil.getString(userTree, UserConstants.REP_AUTHORIZABLE_ID);
+ Tree anotherUser = authorizableFolder.addChild("nodeName");
+ anotherUser.setProperty(userTree.getProperty(JcrConstants.JCR_PRIMARYTYPE));
+ anotherUser.setProperty(userTree.getProperty(JcrConstants.JCR_UUID));
+ anotherUser.setProperty(UserConstants.REP_PRINCIPAL_NAME, TreeUtil.getString(userTree, UserConstants.REP_PRINCIPAL_NAME));
+ anotherUser.setProperty(UserConstants.REP_AUTHORIZABLE_ID, id);
+ root.commit();
+
+ User another = getUserManager(root).getAuthorizable(id, User.class);
+
+ assertEquals(id, another.getID());
+ assertFalse(another.equals(testUser));
+
+ } finally {
+ root.refresh();
+ Tree t = authorizableFolder.getChild("nodeName");
+ if (t.exists()) {
+ t.remove();
+ root.commit();
+ }
+ }
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L4_AuthorizableIdTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L5_UuidTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L5_UuidTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L5_UuidTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L5_UuidTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,141 @@
+/*
+ * 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.user;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.JcrConstants;
+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.api.security.user.UserManager;
+import org.apache.jackrabbit.oak.security.ExerciseUtility;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.apache.jackrabbit.test.AbstractJCRTest;
+
+/**
+ * <pre>
+ * Module: User Management
+ * =============================================================================
+ *
+ * Title: Authorizable Uuid
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * Understand the implementation specific content structure for users and groups.
+ * This particular exercise aims to illustrate the role of jcr:uuid.
+ *
+ * Exercises:
+ *
+ * - Authorizable Node Type Definition:
+ * Look at the node type definition of {@code rep:Authorizable} in {@code builtin_nodetypes.cnd}
+ * and implementation and answer the following questions:
+ *
+ * - Why does a group or user node have a jcr:uuid property?
+ * - What are the constraints JCR mandates for jcr:uuid? Also recap what JCR
+ * states wrt {@link javax.jcr.Item#isSame(javax.jcr.Item)}. What are the
+ * implications for the authorizable implementation as it is today?
+ * - How is the jcr:uuid set in this default implementation?
+ * - What is the jcr:uuid use for in this default implementation?
+ *
+ * - {@link #testIdAndUuidAndIdentifier()}
+ * Use the answers provided above to fix the test. The goal is that you learn
+ * to understand the difference between the ID as exposed by the user management
+ * API and the internal JCR specific node identifiers.
+ *
+ * - {@link #testUuidUponCreation()}
+ * Based on the answers above you should be able to fix the test case.
+ *
+ * </pre>
+ */
+public class L5_UuidTest extends AbstractJCRTest {
+
+ private UserManager userManager;
+ private User testUser;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ userManager = ((JackrabbitSession) superuser).getUserManager();
+ testUser = ExerciseUtility.createTestUser(userManager);
+ superuser.save();
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ try {
+ testUser.remove();
+ superuser.save();
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ private Node getUserNode(User user) throws RepositoryException {
+ String userPath = user.getPath();
+ return superuser.getNode(userPath);
+ }
+
+ public void testIdAndUuidAndIdentifier() throws RepositoryException {
+ Node userNode = getUserNode(testUser);
+
+ assertTrue(userNode.isNodeType(JcrConstants.MIX_REFERENCEABLE));
+
+ String identifier = userNode.getIdentifier();
+ String uuid = userNode.getUUID();
+ String authorizableId = userNode.getProperty(UserConstants.REP_AUTHORIZABLE_ID).getString();
+
+ // EXERCISE: explain why identifier and uuid are expected to be the equal
+ assertEquals(identifier, uuid);
+
+ // EXERCISE: explain why neither uuid nor identifier are expected to be equal to the rep:authoriableId property
+ assertFalse(identifier.equals(authorizableId));
+ assertFalse(uuid.equals(authorizableId));
+
+ String userId = testUser.getID();
+ String expectedUserId = null; // EXERCISE: what is the expected userID ?
+
+ assertEquals(expectedUserId, userId);
+
+ // EXERCISE: what id do you have to use for the lookup on the user manager?
+ String idForLookup = null;
+ User user = userManager.getAuthorizable(idForLookup, User.class);
+
+ Authorizable expectedAuthorizable = null; // EXERCISE
+ assertEquals(expectedAuthorizable, userManager.getAuthorizable(uuid));
+ }
+
+ public void testUuidUponCreation() throws RepositoryException {
+ Node userNode = getUserNode(testUser);
+ String uuid = userNode.getUUID();
+
+ // remove the test user
+ testUser.remove();
+ superuser.save();
+
+ // recreate the same user again
+ testUser = userManager.createUser(testUser.getID(), ExerciseUtility.TEST_PW);
+
+ // EXERCISE: fill the expected identifier.
+ // Q: can you predict the expected identifier?
+ // Q: if yes, why?
+ String expectedUuid = null;
+ assertEquals(expectedUuid, getUserNode(testUser).getUUID());
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L5_UuidTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L6_AuthorizableContentTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L6_AuthorizableContentTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L6_AuthorizableContentTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L6_AuthorizableContentTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,182 @@
+/*
+ * 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.user;
+
+import java.util.List;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.jackrabbit.api.JackrabbitSession;
+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.oak.security.ExerciseUtility;
+import org.apache.jackrabbit.test.AbstractJCRTest;
+
+/**
+ * <pre>
+ * Module: User Management
+ * =============================================================================
+ *
+ * Title: Representation of User|Group Content in the Repository
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * Understand how the default implementation stores user/group information.
+ * After having completed this test you should be familiar with the node
+ * type definitions for rep:Authorizable, rep:User and rep:Group and be
+ * able to map some basic API calls to the individual properties.
+ *
+ * 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 user and group
+ * content.
+ *
+ * Question: Can explain the meaning of all types?
+ * Question: Why are most item definitions protected?
+ * Question: Can you explain which child item definitions are not protected and why?
+ *
+ * - {@link #testUserNode()}
+ * Test case for user nodes.
+ *
+ * - {@link #testUserNodeType()}
+ * What is the primary type of a user node?
+ * Which mixin types are present in addition?
+ *
+ * - {@link #testGroupNode()}
+ * Test case for group nodes.
+ *
+ * - {@link #testGroupNodeType()}
+ * What is the primary type of a group node?
+ * Which mixin types are present in addition?
+ *
+ *
+ * Additional Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * - Discuss why {@link #testUserNode()} doesn't include the password?
+ * - Discuss why {@link #testGroupNode()} doesn't include the 'disabled' flag.
+ *
+ *
+ * Related Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * - {@link L5_UuidTest ()}
+ * - {@link L11_PasswordTest}
+ * - {@link L12_PasswordExpiryTest}
+ * - {@link L8_MembershipTest}
+ *
+ * </pre>
+ *
+ * @see org.apache.jackrabbit.api.security.user.User
+ * @see org.apache.jackrabbit.api.security.user.Group
+ * @see org.apache.jackrabbit.oak.spi.security.user.UserConstants
+ */
+public class L6_AuthorizableContentTest extends AbstractJCRTest {
+
+ private UserManager userManager;
+
+ private User testUser;
+ private Group testGroup;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ userManager = ((JackrabbitSession) superuser).getUserManager();
+ testUser = ExerciseUtility.createTestUser(userManager);
+ testUser.disable("no longer active");
+
+ testGroup = ExerciseUtility.createTestGroup(userManager);
+
+ superuser.save();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ if (testUser != null) {
+ testUser.remove();
+ }
+ if (testGroup != null) {
+ testGroup.remove();
+ }
+ superuser.save();
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ private Node getAuthorizableNode(Authorizable authorizable) throws RepositoryException {
+ String path = authorizable.getPath();
+ return superuser.getNode(path);
+ }
+
+ public void testUserNode() throws RepositoryException {
+ Node node = getAuthorizableNode(testUser);
+
+ String idPropertyName = null; // EXERCISE
+ assertEquals(testUser.getID(), node.getProperty(idPropertyName).getString());
+
+ String principalPropertyName = null; // EXERCISE
+ assertEquals(testUser.getPrincipal().getName(), node.getProperty(principalPropertyName).getString());
+
+ String disabledPropertyName = null; // EXERCISE
+ assertEquals(testUser.getDisabledReason(), node.getProperty(disabledPropertyName));
+ }
+
+ public void testUserNodeType() throws RepositoryException {
+ Node node = getAuthorizableNode(testUser);
+
+ String expectedNodeTypeName = null; // EXERCISE
+ assertEquals(expectedNodeTypeName, node.getPrimaryNodeType().getName());
+
+ List<String> mixinTypes = ImmutableList.of(); // EXERCISE : fill the list
+ for (String mixin : mixinTypes) {
+ assertTrue(node.isNodeType(mixin));
+ }
+ }
+
+ public void testGroupNode() throws RepositoryException {
+ Node node = getAuthorizableNode(testGroup);
+
+ String idPropertyName = null; // EXERCISE
+ assertEquals(testGroup.getID(), node.getProperty(idPropertyName).getString());
+
+ String principalPropertyName = null; // EXERCISE
+ assertEquals(testGroup.getPrincipal().getName(), node.getProperty(principalPropertyName).getString());
+
+ String expectedNodeTypeName = null; // EXERCISE
+ assertEquals(expectedNodeTypeName, node.getPrimaryNodeType().getName());
+ }
+
+ public void testGroupNodeType() throws RepositoryException {
+ Node node = getAuthorizableNode(testGroup);
+
+ String expectedNodeTypeName = null; // EXERCISE
+ assertEquals(expectedNodeTypeName, node.getPrimaryNodeType().getName());
+
+ List<String> mixinTypes = ImmutableList.of(); // EXERCISE : fill the list
+ for (String mixin : mixinTypes) {
+ assertTrue(node.isNodeType(mixin));
+ }
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L6_AuthorizableContentTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L7_AuthorizablePropertiesTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L7_AuthorizablePropertiesTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L7_AuthorizablePropertiesTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L7_AuthorizablePropertiesTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,174 @@
+/*
+ * 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.user;
+
+import java.util.Iterator;
+import java.util.List;
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+
+import com.google.common.collect.ImmutableList;
+import org.apache.jackrabbit.JcrConstants;
+import org.apache.jackrabbit.api.JackrabbitSession;
+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.oak.security.ExerciseUtility;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.apache.jackrabbit.test.AbstractJCRTest;
+
+import static org.junit.Assert.assertArrayEquals;
+
+/**
+ * <pre>
+ * Module: User Management
+ * =============================================================================
+ *
+ * Title: Authorizable Properties
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * The aim of this exercise is to be aware of the API calls to set arbitrary
+ * (non-protected) properties on authorizables.
+ *
+ * Exercises:
+ *
+ * - Overview
+ * List all methods defined on {@link org.apache.jackrabbit.api.security.user.Authorizable}
+ * that allow to read and write arbitrary properties on a given user or group.
+ *
+ * - {@link #testArbitraryProperties()}
+ * Become familiar with the API to read arbitrary properties with an user
+ * or group. Also fill in a list of properties defined by JCR and the
+ * authorizable node types that cannot be obtained using the methods define
+ * on {@link org.apache.jackrabbit.api.security.user.Authorizable}.
+ *
+ * - {@link #testSpecialProperties()}
+ * This tests uses the user properties API to retrieve protected JCR and
+ * user management internal properties.
+ * Fix the tests according to your expectations and your understanding of
+ * the API contract and the implementation.
+ * </pre>
+ *
+ * @see org.apache.jackrabbit.api.security.user.Authorizable
+ */
+public class L7_AuthorizablePropertiesTest extends AbstractJCRTest {
+
+ private final static String EMAIL_REL_PATH = "properties/email";
+ private final static String PETS_REL_PATH = "pets";
+
+ private UserManager userManager;
+
+ private User testUser;
+ private Group testGroup;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ userManager = ((JackrabbitSession) superuser).getUserManager();
+ testUser = ExerciseUtility.createTestUser(userManager);
+ testUser.disable("no longer active");
+
+ testGroup = ExerciseUtility.createTestGroup(userManager);
+ testGroup.addMember(testUser);
+ testGroup.setProperty("Name", superuser.getValueFactory().createValue("Test Group"));
+
+ superuser.save();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ if (testUser != null) {
+ testUser.remove();
+ }
+ if (testGroup != null) {
+ testGroup.remove();
+ }
+ superuser.save();
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ private Node getAuthorizableNode(Authorizable authorizable) throws RepositoryException {
+ String path = authorizable.getPath();
+ return superuser.getNode(path);
+ }
+
+ public void testArbitraryProperties() throws RepositoryException {
+ // set 2 different properties (single and multivalued)
+ testUser.setProperty(EMAIL_REL_PATH, superuser.getValueFactory().createValue("testUser@oak.apache.org"));
+ testUser.setProperty(PETS_REL_PATH, new Value[]{
+ superuser.getValueFactory().createValue("cat"), superuser.getValueFactory().createValue("rabbit")
+ });
+ superuser.save();
+
+
+ Node node = getAuthorizableNode(testUser);
+
+ // EXERCISE: build the list of existing user properties rel paths
+ List<String> userPropertiesPath = ImmutableList.of();
+ for (String relPath : userPropertiesPath) {
+ assertTrue(testUser.hasProperty(relPath));
+ }
+
+ Value[] emailsExpected = testUser.getProperty(EMAIL_REL_PATH);
+ String expectedRelPath = null; // EXERCISE
+ assertEquals(emailsExpected[0], node.getProperty(expectedRelPath).getValue());
+
+ Value[] petsExpected = testUser.getProperty(PETS_REL_PATH);
+ expectedRelPath = null; // EXERCISE
+ assertArrayEquals(petsExpected, node.getProperty(expectedRelPath).getValues());
+
+ // EXERCISE: build a list of protected JCR properties that cannot be accessed using the Authorizable interface
+ List<String> protectedJcrPropertyNames = ImmutableList.of();
+ for (String relPath : protectedJcrPropertyNames) {
+ assertFalse(testUser.hasProperty(relPath));
+ }
+
+ // EXERCISE: build a list of protected properties defined by the authorizable or user node type definitions that cannot be accessed using the Authorizable interface
+ List<String> protectedAuthorizablePropertyNames = ImmutableList.of();
+ for (String relPath : protectedAuthorizablePropertyNames) {
+ assertFalse(testUser.hasProperty(relPath));
+ }
+
+ // remove the properties again
+ testUser.removeProperty(EMAIL_REL_PATH);
+ testUser.removeProperty(PETS_REL_PATH);
+ superuser.save();
+ }
+
+ public void testSpecialProperties() throws RepositoryException {
+ List<String> expectedGroupPropNames = null; // EXERCISE
+ Iterator<String> propNames = testGroup.getPropertyNames();
+
+ while (propNames.hasNext()) {
+ assertTrue(expectedGroupPropNames.remove(propNames.next()));
+ }
+ assertTrue(expectedGroupPropNames.isEmpty());
+
+ Boolean hasPrimaryType = null; // EXERCISE
+ assertEquals(hasPrimaryType.booleanValue(), testGroup.hasProperty(JcrConstants.JCR_PRIMARYTYPE));
+
+ Value[] expectedMembers = null; // EXERCISE
+ Value[] members = testGroup.getProperty(UserConstants.REP_MEMBERS);
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L7_AuthorizablePropertiesTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L8_MembershipTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L8_MembershipTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L8_MembershipTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L8_MembershipTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,290 @@
+/*
+ * 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.user;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.JcrConstants;
+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.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.security.ExerciseUtility;
+import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
+import org.apache.jackrabbit.oak.util.TreeUtil;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * <pre>
+ * Module: User Management
+ * =============================================================================
+ *
+ * Title: Group Membership
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * After having completed this exercise you should be able to manage group
+ * membership relations using the Jackrabbit User Management API and understand
+ * the basic design on how group membership is store and handled in the
+ * Oak repository.
+ *
+ * Exercises:
+ *
+ * - Overview
+ * Take a look at the Jackrabbit User Management API and how group membership
+ * is being edited (in {@link org.apache.jackrabbit.api.security.user.Group}
+ * and discovered in both directions on {@link org.apache.jackrabbit.api.security.user.Group}
+ * and {@link org.apache.jackrabbit.api.security.user.Authorizable}.
+ *
+ * - {@link #testAddRemoveMembers()}
+ * Add (and remove) members to the predefined groups such that the test passes.
+ *
+ * - {@link #testDeclaredMembership()}
+ * This test illustrates how declared members are retrieved from a group and
+ * how to obtain the declared group membership of a given authorizable (user or
+ * group).
+ *
+ * Question: This test is executed with full permission. Can you elaborate
+ * what happens if the editing session has limited read access on the user/group
+ * tree(s)?
+ *
+ * - {@link #testInheritedMembership()}
+ * This test illustrates how all members of a group are retrieved and
+ * how to obtain full group membership of a given authorizable (user or
+ * group). Complete the test such that it passes.
+ *
+ * - {@link #testMembersContentStructure()}
+ * In order to complete this exercise look at the built-in node types and
+ * identify those types that deal with group membership.
+ * Once you are familiar with the node type definitions look at
+ * > {@link org.apache.jackrabbit.oak.security.user.MembershipProvider} and
+ * > {@link org.apache.jackrabbit.oak.security.user.MembershipWriter}
+ * and how they deal with massive amount of members on a given group.
+ * Finally fix the test case :-)
+ *
+ *
+ * Additional Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * As you can see from the API calls present as of Jackrabbit API 2.10 you
+ * currently need to have an existing authorizable at hand in order to add
+ * (or remove) it as member of a given group.
+ * Since group membership is stored as {@link javax.jcr.PropertyType#WEAKREFERENCE}
+ * the repository is not obligated to enforce the validity of the references
+ * and thus might choose to create membership references that cannot (yet) be
+ * resolved.
+ *
+ * Look at the following unit tests present with the oak-jcr module and observe
+ * how the configured {@link org.apache.jackrabbit.oak.spi.xml.ImportBehavior}
+ * affects the import of group-membership information that cannot be resolved
+ * to an existing authorizable:
+ *
+ * - {@link org.apache.jackrabbit.oak.jcr.security.user.GroupImportBestEffortTest#testImportNonExistingMemberBestEffort()}
+ * - {@link org.apache.jackrabbit.oak.jcr.security.user.GroupImportAbortTest#testImportNonExistingMemberAbort()}
+ * - {@link org.apache.jackrabbit.oak.jcr.security.user.GroupImportIgnoreTest#testImportNonExistingMemberIgnore()} ()}
+ *
+ * Exercises
+ *
+ * 1. Walk through the XML import and take a close look at
+ * {@link org.apache.jackrabbit.oak.security.user.UserImporter}, where the XML
+ * of the protected items defined with the various authorizable node types
+ * are being handled. Compare the differences wrt to the import behavior.
+ *
+ * 2. Discuss possible use-cases where creating a group with members that don't
+ * (yet) exist (anymore) might be helpful (or even required).
+ *
+ *
+ * Advanced Exercise:
+ * -----------------------------------------------------------------------------
+ *
+ * Having completed the additional exercises wrt {@link org.apache.jackrabbit.oak.spi.xml.ImportBehavior}
+ * and the XML import of non-existing group members, you may want to complete
+ * following exercise.
+ *
+ * Question: How might the implementation of the API extensions proposed in
+ * <a href="https://issues.apache.org/jira/browse/JCR-3880">JCR-3880</a> could
+ * look like such that the implementation both matches the API contract and
+ * is consistent with the XML import?
+ *
+ * </pre>
+ *
+ * @see org.apache.jackrabbit.api.security.user.Authorizable#declaredMemberOf()
+ * @see org.apache.jackrabbit.api.security.user.Authorizable#memberOf()
+ * @see org.apache.jackrabbit.api.security.user.Group#isMember(org.apache.jackrabbit.api.security.user.Authorizable)
+ * @see org.apache.jackrabbit.api.security.user.Group#isDeclaredMember(org.apache.jackrabbit.api.security.user.Authorizable)
+ * @see org.apache.jackrabbit.api.security.user.Group#getMembers()
+ * @see org.apache.jackrabbit.api.security.user.Group#getDeclaredMembers()
+ * @see org.apache.jackrabbit.api.security.user.Group#addMember(org.apache.jackrabbit.api.security.user.Authorizable)
+ * @see org.apache.jackrabbit.api.security.user.Group#removeMember(org.apache.jackrabbit.api.security.user.Authorizable)
+ */
+public class L8_MembershipTest extends AbstractSecurityTest {
+
+ private User user;
+ private Group group;
+ private Group group2;
+ private Group group3;
+
+ private List<Authorizable> toRemove = new ArrayList<Authorizable>();
+
+ @Override
+ public void before() throws Exception {
+ super.before();
+
+ user = (User) createNewAuthorizable(false);
+ group = (Group) createNewAuthorizable(true);
+ group2 = (Group) createNewAuthorizable(true);
+ group3 = (Group) createNewAuthorizable(true);
+
+ root.commit();
+ }
+
+ @Override
+ public void after() throws Exception {
+ try {
+ for (Authorizable a : toRemove) {
+ a.remove();
+ }
+ root.commit();
+ } finally {
+ super.after();
+ }
+ }
+
+ private Authorizable createNewAuthorizable(boolean isGroup) throws RepositoryException {
+ UserManager uMgr = getUserManager(root);
+ Authorizable a = (isGroup) ? ExerciseUtility.createTestGroup(uMgr) : ExerciseUtility.createTestUser(uMgr);
+ toRemove.add(a);
+ return a;
+ }
+
+ @Test
+ public void testAddRemoveMembers() throws RepositoryException, CommitFailedException {
+ // EXERCISE: add group members such that the following test-cases passes.
+ root.commit();
+
+ assertTrue(group.isDeclaredMember(user));
+ assertFalse(group2.isDeclaredMember(user));
+ assertFalse(group3.isDeclaredMember(user));
+ assertTrue(group2.isMember(user));
+ assertTrue(group3.isMember(user));
+
+ Boolean isDeclaredMember = null; // EXERCISE
+ assertEquals(isDeclaredMember, group.isDeclaredMember(group2));
+
+ isDeclaredMember = null; // EXERCISE
+ assertEquals(isDeclaredMember, group3.isDeclaredMember(group));
+
+ Boolean isMember = null; // EXERCISE
+ assertEquals(isMember, group.isMember(group2));
+
+ isMember = null; // EXERCISE
+ assertEquals(isMember, group3.isMember(group));
+
+ // EXERCISE: now change the group membership such that the following assertions pass
+ root.commit();
+
+ assertFalse(group.isMember(user));
+ assertTrue(group.isMember(group2));
+ assertTrue(group3.isMember(group2));
+ assertTrue(group3.isMember(group));
+ assertTrue(group3.isMember(user));
+ }
+
+ @Test
+ public void testDeclaredMembership() throws RepositoryException, CommitFailedException {
+ group.addMember(group2);
+ group2.addMember(group3);
+ group3.addMember(user);
+ root.commit();
+
+ Set<Group> expectedGroups = null; // EXERCISE
+ Iterator<Group> groups = user.declaredMemberOf();
+ while (groups.hasNext()) {
+ assertTrue(expectedGroups.remove(groups.next()));
+ }
+ assertTrue(expectedGroups.isEmpty());
+
+ Set<Authorizable> expectedMembers = null; // EXERCISE
+ Iterator<Authorizable> memberIterator = group.getDeclaredMembers();
+ while (memberIterator.hasNext()) {
+ assertTrue(expectedMembers.remove(memberIterator.next()));
+ }
+ assertTrue(expectedMembers.isEmpty());
+ }
+
+ @Test
+ public void testInheritedMembership() throws RepositoryException, CommitFailedException {
+ group.addMember(group2);
+ group.addMember(group3);
+ group3.addMember(user);
+ root.commit();
+
+ Set<Group> groups = null; // EXERCISE
+ Iterator<Group> groupIterator = user.memberOf();
+ while (groupIterator.hasNext()) {
+ Group gr = groupIterator.next();
+ assertTrue(groups.remove(gr));
+ }
+ assertTrue(groups.isEmpty());
+
+ Set<Authorizable> expectedMembers = null; // EXERCISE
+ Iterator<Authorizable> memberIterator = group.getMembers();
+ while (memberIterator.hasNext()) {
+ assertTrue(expectedMembers.remove(memberIterator.next()));
+ }
+ assertTrue(expectedMembers.isEmpty());
+ }
+
+ @Test
+ public void testMembersContentStructure() throws RepositoryException, CommitFailedException {
+ int size = new MembershipWriter().getMembershipSizeThreshold() * 5;
+
+ List<String> memberUuids = new ArrayList<String>();
+ for (int i = 0; i < size; i++) {
+ Authorizable user = createNewAuthorizable(false);
+ String uuid = TreeUtil.getString(root.getTree(user.getPath()), JcrConstants.JCR_UUID);
+ //assertNotNull(uuid);
+ memberUuids.add(uuid);
+ group.addMember(user);
+ }
+ root.commit();
+
+ Tree groupTree = root.getTree(group.getPath());
+ Iterator<String> values = groupTree.getProperty(UserConstants.REP_MEMBERS).getValue(Type.STRINGS).iterator();
+ while (values.hasNext()) {
+ assertTrue(memberUuids.remove(values.next()));
+ }
+ assertFalse(memberUuids.isEmpty());
+
+ // EXERCISE: retrieve the rest of the member-information stored with the group
+ // EXERCISE: by looking at the tree structure created by the MembershipWriter
+
+ assertTrue(memberUuids.isEmpty());
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L8_MembershipTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L9_RemoveAuthorizableTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L9_RemoveAuthorizableTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L9_RemoveAuthorizableTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L9_RemoveAuthorizableTest.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.user;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.Privilege;
+
+import org.apache.jackrabbit.JcrConstants;
+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.api.security.user.UserManager;
+import org.apache.jackrabbit.commons.jackrabbit.authorization.AccessControlUtils;
+import org.apache.jackrabbit.oak.plugins.lock.LockConstants;
+import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
+import org.apache.jackrabbit.oak.security.ExerciseUtility;
+import org.apache.jackrabbit.test.AbstractJCRTest;
+import org.apache.jackrabbit.test.NotExecutableException;
+
+/**
+ * <pre>
+ * Module: User Management
+ * =============================================================================
+ *
+ * Title: Remove Authorizables
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * Understand why we strongly recommend not to remove (and recycle) user/group
+ * accounts.
+ *
+ * Exercises:
+ *
+ * - {@link #testAccessControlEntry()}
+ * Test case illustrating the effect of removing the principal (for simplicity
+ * represented by a test-user) referenced in an access control entry.
+ * Explain the expected behavior and fix the test if necessary
+ *
+ * - {@link #testCreatedBy()}
+ * Test case illustrating the effect of removing a user which created node
+ * that is of type 'mix:created'.
+ * Explain the expected behavior and fix the test if necessary
+ *
+ * - {@link #testLastModifiedBy()}
+ * Test case illustrating the effect of removing a user which added the mixin
+ * 'mix:lastModified' to the test node.
+ * Explain the expected behavior and fix the test if necessary
+ *
+ * - {@link #testLock()}
+ * Test case illustrating the effect of removing a user which created a
+ * open-scoped lock.
+ *
+ * - Based on the experiences from perfoming the above tests, summarize the effect
+ * of removing an existing user and potentially re-using the same ID
+ * at a later point.
+ *
+ * Question: What are the implications from a security point of view
+ * Question: What are possible consequences from a legal point of view
+ *
+ * - Use the user management API to identify alterntive ways such that you don't
+ * need to remove the user.
+ *
+ *
+ * Additional Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * In a OSGI-based Oak installation (Sling|Granite|CQ) you can extend this exercise:
+ *
+ * - Look for additional node types that store references to user or principals.
+ * List node types and the properties
+ *
+ * - Inspect application code: can you find additional references to user/principals
+ * stored?
+ * Provide a list and discuss the impact from a security|legel point of view
+ *
+ * - Inspect the various log files for user or principal references
+ * Discuss the legal implications of re-using them for different entities (subjects).
+ *
+ *
+ * Related Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * - {@link L10_RemovalAndMembershipTest ()}
+ *
+ * </pre>
+ *
+ */
+public class L9_RemoveAuthorizableTest extends AbstractJCRTest {
+
+ private UserManager userManager;
+
+ private User testUser;
+ private Session testSession;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ userManager = ((JackrabbitSession) superuser).getUserManager();
+ testUser = ExerciseUtility.createTestUser(userManager);
+
+ superuser.save();
+
+ // setup full access for test-user on the test-node
+ Privilege[] privileges = AccessControlUtils.privilegesFromNames(superuser, Privilege.JCR_ALL);
+ if (!AccessControlUtils.addAccessControlEntry(superuser, testRoot, testUser.getPrincipal(), privileges, true)) {
+ throw new NotExecutableException();
+ }
+ superuser.save();
+
+ testSession = getHelper().getRepository().login(ExerciseUtility.getTestCredentials(testUser.getID()));
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ try {
+ if (testSession != null) {
+ testSession.logout();
+ }
+ if (testUser != null) {
+ testUser.remove();
+ }
+ superuser.save();
+ } finally {
+ super.tearDown();
+ }
+ }
+
+ private void removeTestUser() throws RepositoryException {
+ testUser.remove();
+ superuser.save();
+ testUser = null;
+ }
+
+ private Node getAuthorizableNode(Authorizable authorizable) throws RepositoryException {
+ String path = authorizable.getPath();
+ return superuser.getNode(path);
+ }
+
+ public void testAccessControlEntry() throws RepositoryException, NotExecutableException {
+ // remove test user
+ removeTestUser();
+
+ boolean found = false;
+ AccessControlList acl = AccessControlUtils.getAccessControlList(superuser, testRoot);
+ if (acl != null) {
+ for (AccessControlEntry ace : acl.getAccessControlEntries()) {
+ if (testUser.getPrincipal().getName().equals(ace.getPrincipal().getName())) {
+ found = true;
+ }
+ }
+ }
+
+ // EXERCISE: do you expect the ACE for test-principal to be still present? explain why and fix the test if necessary.
+ assertTrue(found);
+ }
+
+ public void testCreatedBy() throws RepositoryException {
+ Node testNode = testSession.getNode(testRoot);
+ Node folder = testNode.addNode("folder", JcrConstants.NT_FOLDER);
+ testSession.save();
+
+ // EXERCISE: explain why the folder node must have a jcr:created property.
+ assertTrue(folder.hasProperty(NodeTypeConstants.JCR_CREATEDBY));
+ assertEquals(testSession.getUserID(), folder.getProperty(NodeTypeConstants.JCR_CREATEDBY).getString());
+
+ removeTestUser();
+ testSession.refresh(false);
+
+ // EXERCISE: do you expect jcr:createdBy property to be still present? explain why and fix the test if necessary.
+ assertTrue(folder.hasProperty(NodeTypeConstants.JCR_CREATEDBY));
+ }
+
+ public void testLastModifiedBy() throws RepositoryException {
+ Node testNode = testSession.getNode(testRoot);
+ testNode.addMixin(NodeTypeConstants.MIX_LASTMODIFIED);
+ testNode.setProperty(propertyName1, "any value");
+ testSession.save();
+
+ assertTrue(testNode.hasProperty(NodeTypeConstants.JCR_LASTMODIFIEDBY));
+ assertEquals(testSession.getUserID(), testNode.getProperty(NodeTypeConstants.JCR_LASTMODIFIEDBY).getString());
+
+ removeTestUser();
+ testSession.refresh(false);
+
+ // EXERCISE: do you expect the property to be still present? explain why and fix the test if necessary.
+ assertTrue(testNode.hasProperty(NodeTypeConstants.JCR_LASTMODIFIEDBY));
+ }
+
+ public void testLock() throws RepositoryException {
+ Node testNode = testSession.getNode(testRoot);
+ testNode.addMixin(JcrConstants.MIX_LOCKABLE);
+ testSession.save();
+
+ testNode.lock(true, false);
+
+ try {
+ assertTrue(testNode.hasProperty(LockConstants.JCR_LOCKOWNER));
+ assertEquals(testSession.getUserID(), testNode.getProperty(LockConstants.JCR_LOCKOWNER).getString());
+
+ removeTestUser();
+ testSession.refresh(false);
+
+ // EXERCISE: do you expect the property to be still present? explain why and fix the test if necessary.
+ assertTrue(testNode.hasProperty(LockConstants.JCR_LOCKOWNER));
+
+ } finally {
+ testNode.unlock();
+ }
+ }
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/L9_RemoveAuthorizableTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/action/L1_IntroductionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/action/L1_IntroductionTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/action/L1_IntroductionTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/action/L1_IntroductionTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,49 @@
+/*
+ * 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.user.action;
+
+import org.apache.jackrabbit.oak.AbstractSecurityTest;
+
+/**
+ * <pre>
+ * Module: User Management
+ * =============================================================================
+ *
+ * Title: Introduction to Authorizable Actions
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * TODO
+ *
+ * Exercises:
+ *
+ * - {@link #TODO}
+ *
+ *
+ * Additional Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * TODO
+ *
+ * </pre>
+ *
+ * @see TODO
+ */
+public class L1_IntroductionTest extends AbstractSecurityTest {
+
+
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/action/L1_IntroductionTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/action/L2_AuthorizableActionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/action/L2_AuthorizableActionTest.java?rev=1686235&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/action/L2_AuthorizableActionTest.java (added)
+++ jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/action/L2_AuthorizableActionTest.java Thu Jun 18 14:30:16 2015
@@ -0,0 +1,49 @@
+/*
+ * 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.user.action;
+
+import org.apache.jackrabbit.oak.AbstractSecurityTest;
+
+/**
+ * <pre>
+ * Module: User Management
+ * =============================================================================
+ *
+ * Title: Authorizable Action in Detail
+ * -----------------------------------------------------------------------------
+ *
+ * Goal:
+ * TODO
+ *
+ * Exercises:
+ *
+ * - {@link #TODO}
+ *
+ *
+ * Additional Exercises:
+ * -----------------------------------------------------------------------------
+ *
+ * TODO
+ *
+ * </pre>
+ *
+ * @see TODO
+ */
+public class L2_AuthorizableActionTest extends AbstractSecurityTest {
+
+ // TODO
+}
\ No newline at end of file
Propchange: jackrabbit/oak/trunk/oak-exercise/src/test/java/org/apache/jackrabbit/oak/security/user/action/L2_AuthorizableActionTest.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/oak/trunk/pom.xml
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/pom.xml?rev=1686235&r1=1686234&r2=1686235&view=diff
==============================================================================
--- jackrabbit/oak/trunk/pom.xml (original)
+++ jackrabbit/oak/trunk/pom.xml Thu Jun 18 14:30:16 2015
@@ -55,6 +55,7 @@
<module>oak-pojosr</module>
<module>oak-authorization-cug</module>
<module>oak-remote</module>
+ <module>oak-exercise</module>
</modules>
<scm>