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 dj...@apache.org on 2016/08/17 14:21:08 UTC
svn commit: r1756639 [3/5] - in /jackrabbit/oak/branches/1.2: ./
oak-commons/ oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/
oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/identifier/
oak-core/src/main/java/org/apache/jackrabbit...
Modified: jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/MembershipProviderTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/MembershipProviderTest.java?rev=1756639&r1=1756638&r2=1756639&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/MembershipProviderTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/MembershipProviderTest.java Wed Aug 17 14:21:07 2016
@@ -16,17 +16,25 @@
*/
package org.apache.jackrabbit.oak.security.user;
+import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import java.util.Set;
-
+import javax.annotation.Nonnull;
import javax.jcr.RepositoryException;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
+import com.google.common.collect.Maps;
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.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Tree;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
@@ -39,56 +47,53 @@ import org.junit.Test;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
/**
* Tests large group and user graphs.
* <ul>
- * <li>{@link #NUM_USERS} users</li>
- * <li>{@link #NUM_GROUPS} groups</li>
- * <li>1 group with all users</li>
- * <li>1 user with all groups</li>
+ * <li>{@link #NUM_USERS} users</li>
+ * <li>{@link #NUM_GROUPS} groups</li>
+ * <li>1 group with all users</li>
+ * <li>1 user with all groups</li>
* </ul>
*
* @since OAK 1.0
*/
-public class MembershipProviderTest extends AbstractSecurityTest {
+public class MembershipProviderTest extends AbstractSecurityTest implements UserConstants {
private static final int NUM_USERS = 1000;
private static final int NUM_GROUPS = 1000;
private static final int SIZE_TH = 10;
private UserManagerImpl userMgr;
+ private MembershipProvider mp;
private Set<String> testUsers = new HashSet<String>();
private Set<String> testGroups = new HashSet<String>();
@Before
public void before() throws Exception {
super.before();
- testUsers.clear();
- testGroups.clear();
userMgr = new UserManagerImpl(root, namePathMapper, getSecurityProvider());
- // set the membership size threshold low for testing
- userMgr.getMembershipProvider().setMembershipSizeThreshold(SIZE_TH);
+ mp = userMgr.getMembershipProvider();
+ // set the threshold low for testing
+ mp.setMembershipSizeThreshold(SIZE_TH);
}
@After
public void after() throws Exception {
try {
- for (String authId: testGroups) {
- Authorizable auth = userMgr.getAuthorizable(authId);
- if (auth != null) {
- auth.remove();
- }
- }
- for (String authId: testUsers) {
- Authorizable auth = userMgr.getAuthorizable(authId);
+ for (String path : Iterables.concat(testUsers, testGroups)) {
+ Authorizable auth = userMgr.getAuthorizableByPath(path);
if (auth != null) {
auth.remove();
}
}
root.commit();
} finally {
+ testUsers.clear();
+ testGroups.clear();
super.after();
}
}
@@ -96,24 +101,24 @@ public class MembershipProviderTest exte
@Test
public void testManyMembers() throws Exception {
Set<String> members = new HashSet<String>();
- Group grp = createGroup();
- for (int i=0; i<NUM_USERS; i++) {
+ Group grp = createGroup();
+ for (int i = 0; i < NUM_USERS; i++) {
User usr = createUser();
grp.addMember(usr);
members.add(usr.getID());
}
root.commit();
- checkMembers(grp, members);
+ assertMembers(grp, members);
// also check storage structure
Tree tree = root.getTree(grp.getPath());
assertEquals(
"rep:members property must have correct number of references",
SIZE_TH,
- tree.getProperty(UserConstants.REP_MEMBERS).count()
+ tree.getProperty(REP_MEMBERS).count()
);
- Tree membersList = tree.getChild(UserConstants.REP_MEMBERS_LIST);
+ Tree membersList = tree.getChild(REP_MEMBERS_LIST);
assertTrue(
"rep:memberList must exist",
membersList.exists()
@@ -121,7 +126,7 @@ public class MembershipProviderTest exte
assertEquals(
"rep:memberList must have correct primary type.",
- UserConstants.NT_REP_MEMBER_REFERENCES_LIST,
+ NT_REP_MEMBER_REFERENCES_LIST,
membersList.getProperty(JcrConstants.JCR_PRIMARYTYPE).getValue(Type.STRING)
);
@@ -136,7 +141,7 @@ public class MembershipProviderTest exte
public void testManyMemberships() throws Exception {
Set<String> memberships = new HashSet<String>();
User usr = createUser();
- for (int i=0; i<NUM_GROUPS; i++) {
+ for (int i = 0; i < NUM_GROUPS; i++) {
Group grp = createGroup();
grp.addMember(usr);
memberships.add(grp.getID());
@@ -155,17 +160,17 @@ public class MembershipProviderTest exte
public void testNestedMembers() throws Exception {
Set<String> members = new HashSet<String>();
Set<String> declaredMembers = new HashSet<String>();
- Group grp = createGroup();
- for (int i=0; i<10; i++) {
+ Group grp = createGroup();
+ for (int i = 0; i < 10; i++) {
Group g1 = createGroup();
grp.addMember(g1);
members.add(g1.getID());
declaredMembers.add(g1.getID());
- for (int j=0; j<10; j++) {
+ for (int j = 0; j < 10; j++) {
Group g2 = createGroup();
g1.addMember(g2);
members.add(g2.getID());
- for (int k=0; k<10; k++) {
+ for (int k = 0; k < 10; k++) {
User usr = createUser();
g2.addMember(usr);
members.add(usr.getID());
@@ -174,7 +179,7 @@ public class MembershipProviderTest exte
}
root.commit();
- checkMembers(grp, members);
+ assertMembers(grp, members);
Iterator<Authorizable> iter = grp.getDeclaredMembers();
while (iter.hasNext()) {
@@ -187,14 +192,14 @@ public class MembershipProviderTest exte
@Test
public void testNestedMemberships() throws Exception {
Set<String> memberships = new HashSet<String>();
- User user = createUser();
+ User user = createUser();
Group grp = createGroup();
memberships.add(grp.getID());
- for (int i=0; i<10; i++) {
+ for (int i = 0; i < 10; i++) {
Group g1 = createGroup();
grp.addMember(g1);
memberships.add(g1.getID());
- for (int j=0; j<10; j++) {
+ for (int j = 0; j < 10; j++) {
Group g2 = createGroup();
g1.addMember(g2);
memberships.add(g2.getID());
@@ -215,8 +220,8 @@ public class MembershipProviderTest exte
public void testRemoveMembers() throws Exception {
Set<String> members = new HashSet<String>();
String[] users = new String[NUM_USERS];
- Group grp = createGroup();
- for (int i=0; i<NUM_USERS; i++) {
+ Group grp = createGroup();
+ for (int i = 0; i < NUM_USERS; i++) {
User usr = createUser();
grp.addMember(usr);
members.add(usr.getID());
@@ -226,24 +231,24 @@ public class MembershipProviderTest exte
// remove the first TH users, this should remove all references from rep:members in the group node and remove
// the rep:members property
- for (int i=0; i<SIZE_TH; i++) {
+ for (int i = 0; i < SIZE_TH; i++) {
Authorizable auth = userMgr.getAuthorizable(users[i]);
members.remove(users[i]);
grp.removeMember(auth);
}
root.commit();
- checkMembers(grp, members);
+ assertMembers(grp, members);
// also check storage structure
Tree tree = root.getTree(grp.getPath());
assertNull(
"rep:members property not exist",
- tree.getProperty(UserConstants.REP_MEMBERS)
+ tree.getProperty(REP_MEMBERS)
);
// now add TH/2 again.
- for (int i=0; i<SIZE_TH/2; i++) {
+ for (int i = 0; i < SIZE_TH / 2; i++) {
Authorizable auth = userMgr.getAuthorizable(users[i]);
members.add(users[i]);
grp.addMember(auth);
@@ -253,47 +258,45 @@ public class MembershipProviderTest exte
assertEquals(
"rep:members property must have correct number of references",
SIZE_TH / 2,
- tree.getProperty(UserConstants.REP_MEMBERS).count()
+ tree.getProperty(REP_MEMBERS).count()
);
- checkMembers(grp, members);
+ assertMembers(grp, members);
// now remove the users 20-30, this should remove the 2nd overflow node
- for (int i=2*SIZE_TH; i< (3*SIZE_TH); i++) {
+ for (int i = 2 * SIZE_TH; i < (3 * SIZE_TH); i++) {
Authorizable auth = userMgr.getAuthorizable(users[i]);
members.remove(users[i]);
grp.removeMember(auth);
}
root.commit();
- checkMembers(grp, members);
+ assertMembers(grp, members);
- Tree membersList = tree.getChild(UserConstants.REP_MEMBERS_LIST);
+ Tree membersList = tree.getChild(REP_MEMBERS_LIST);
assertFalse(
"the first overflow node must not exist",
membersList.getChild("1").exists()
);
// now add 10 users and check if the "1" node exists again
- for (int i=2*SIZE_TH; i< (3*SIZE_TH); i++) {
+ for (int i = 2 * SIZE_TH; i < (3 * SIZE_TH); i++) {
Authorizable auth = userMgr.getAuthorizable(users[i]);
members.add(users[i]);
grp.addMember(auth);
}
root.commit();
- checkMembers(grp, members);
+ assertMembers(grp, members);
- membersList = tree.getChild(UserConstants.REP_MEMBERS_LIST);
- assertTrue(
- "the first overflow node must not exist",
- membersList.getChild("1").exists()
+ membersList = tree.getChild(REP_MEMBERS_LIST);
+ assertTrue("the first overflow node must not exist", membersList.getChild("1").exists()
);
}
@Test
public void testAddMembersAgain() throws Exception {
Set<String> members = new HashSet<String>();
- Group grp = createGroup();
- for (int i=0; i<NUM_USERS; i++) {
+ Group grp = createGroup();
+ for (int i = 0; i < NUM_USERS; i++) {
User usr = createUser();
grp.addMember(usr);
members.add(usr.getID());
@@ -308,45 +311,271 @@ public class MembershipProviderTest exte
@Test
public void testAddMembersAgainOnMembershipProvider() throws Exception {
Set<String> memberPaths = new HashSet<String>();
- Group grp = createGroup();
- for (int i=0; i<NUM_USERS; i++) {
+ Group grp = createGroup();
+ for (int i = 0; i < NUM_USERS; i++) {
User usr = createUser();
grp.addMember(usr);
memberPaths.add(usr.getPath());
}
root.commit();
-
- MembershipProvider mp = userMgr.getMembershipProvider();
Tree groupTree = root.getTree(grp.getPath());
for (String path : memberPaths) {
Tree memberTree = root.getTree(path);
assertFalse(mp.addMember(groupTree, memberTree));
- assertFalse(mp.addMember(groupTree, TreeUtil.getString(memberTree, JcrConstants.JCR_UUID)));
+ assertFalse(mp.addMember(groupTree, memberTree));
+
+ String memberId = TreeUtil.getString(memberTree, REP_AUTHORIZABLE_ID);
+ Map<String, String> m = new HashMap<String, String>(1);
+ m.put(TreeUtil.getString(memberTree, JcrConstants.JCR_UUID), memberId);
+
+ Set<String> failed = mp.addMembers(groupTree, m);
+ assertFalse(failed.isEmpty());
+ assertTrue(failed.contains(memberId));
+ }
+ }
+
+ @Test
+ public void testIsDeclaredMemberTransient() throws Exception {
+ Group g = createGroup();
+ List<Authorizable> members = createMembers(g, NUM_USERS/2);
+
+ Tree groupTree = getTree(g);
+
+ // test declared members with transient modifications
+ for (Authorizable a : members) {
+ assertTrue(mp.isDeclaredMember(groupTree, getTree(a)));
+ }
+ }
+
+ @Test
+ public void testIsDeclaredMember() throws Exception {
+ Group g = createGroup();
+ List<Authorizable> members = createMembers(g, NUM_USERS/2);
+ root.commit();
+
+ Tree groupTree = getTree(g);
+
+ // test declared members after commit
+ for (Authorizable a : members) {
+ assertTrue(mp.isDeclaredMember(groupTree, getTree(a)));
+ }
+ }
+
+ @Test
+ public void testIsDeclaredMemberFew() throws Exception {
+ Group g = createGroup();
+ Group m1 = createGroup();
+ User m2 = createUser();
+
+ g.addMembers(m1.getID(), m2.getID());
+
+ Tree groupTree = getTree(g);
+ assertFalse(groupTree.hasChild(REP_MEMBERS_LIST));
+
+ // test declared members with transient modifications
+ assertTrue(mp.isDeclaredMember(groupTree, getTree(m1)));
+ assertTrue(mp.isDeclaredMember(groupTree, getTree(m2)));
+
+ // ... and after commit
+ root.commit();
+ assertTrue(mp.isDeclaredMember(groupTree, getTree(m1)));
+ assertTrue(mp.isDeclaredMember(groupTree, getTree(m2)));
+ }
+
+ @Test
+ public void testIsMemberTransient() throws Exception {
+ Group g = createGroup();
+ Group g2 = createGroup();
+ g.addMember(g2);
+
+ List<Authorizable> members = createMembers(g2, 50);
+
+ Tree groupTree = getTree(g);
+
+ // test members with transient modifications
+ for (Authorizable a : members) {
+ Tree tree = getTree(a);
+ assertFalse(mp.isDeclaredMember(groupTree, tree));
+ assertTrue(mp.isMember(groupTree, tree));
+ }
+ }
+
+ @Test
+ public void testIsMember() throws Exception {
+ Group g = createGroup();
+ Group g2 = createGroup();
+ g.addMember(g2);
+
+ List<Authorizable> members = createMembers(g2, NUM_USERS/2);
+ root.commit();
+
+ // test members after commit
+ Tree groupTree = getTree(g);
+ for (Authorizable a : members) {
+ Tree tree = getTree(a);
+ assertFalse(mp.isDeclaredMember(groupTree, tree));
+ assertTrue(mp.isMember(groupTree, tree));
}
}
+ @Test
+ public void testIsMemberFew() throws Exception {
+ Group g = createGroup();
+ Group g2 = createGroup();
+ g.addMember(g2);
+
+ User m1 = createUser();
+ Group m2 = createGroup();
+ g2.addMember(m1);
+ g2.addMember(m2);
+
+ Tree groupTree = getTree(g);
+
+ // test members with transient modifications
+ assertFalse(mp.isDeclaredMember(groupTree, getTree(m1)));
+ assertFalse(mp.isDeclaredMember(groupTree, getTree(m2)));
+ assertTrue(mp.isMember(groupTree, getTree(m1)));
+ assertTrue(mp.isMember(groupTree, getTree(m2)));
+
+ // ... and after commit
+ root.commit();
+ assertFalse(mp.isDeclaredMember(groupTree, getTree(m1)));
+ assertFalse(mp.isDeclaredMember(groupTree, getTree(m2)));
+ assertTrue(mp.isMember(groupTree, getTree(m1)));
+ assertTrue(mp.isMember(groupTree, getTree(m2)));
+ }
+
+ @Test
+ public void testTransientInMembersList() throws Exception {
+ Group g = createGroup();
+ createMembers(g, NUM_USERS/2);
+ root.commit();
+
+ // add another transient member that will end up in the members-ref-list
+ User u = createUser();
+ g.addMember(u);
+
+ Tree groupTree = getTree(g);
+ Tree memberTree = getTree(u);
+
+ assertTrue(mp.isDeclaredMember(groupTree, memberTree));
+ assertTrue(mp.isMember(groupTree, memberTree));
+
+ assertFalse(Iterators.contains(mp.getMembership(memberTree, false), groupTree.getPath()));
+ assertFalse(Iterators.contains(mp.getMembership(memberTree, true), groupTree.getPath()));
+ root.commit();
+ assertTrue(Iterators.contains(mp.getMembership(memberTree, false), groupTree.getPath()));
+ assertTrue(Iterators.contains(mp.getMembership(memberTree, true), groupTree.getPath()));
+ }
+
+ @Test
+ public void testNoMember() throws Exception {
+ Group g = createGroup();
+ Group notMember = createGroup();
+ User notMember2 = createUser();
+
+ assertFalse(g.isDeclaredMember(notMember));
+ assertFalse(g.isDeclaredMember(notMember2));
+
+ assertFalse(g.isMember(notMember));
+ assertFalse(g.isMember(notMember2));
+
+ root.commit();
+
+ assertFalse(g.isDeclaredMember(notMember));
+ assertFalse(g.isDeclaredMember(notMember2));
+
+ assertFalse(g.isMember(notMember));
+ assertFalse(g.isMember(notMember2));
+ }
+
+ @Test
+ public void testAddMembersExceedThreshold() throws Exception {
+ Tree groupTree = root.getTree(createGroup().getPath());
+
+ // 1. add array of 21 memberIDs exceeding the threshold
+ Map<String, String> memberIds = createIdMap(0, 21);
+ mp.addMembers(groupTree, memberIds);
+
+ PropertyState repMembers = groupTree.getProperty(REP_MEMBERS);
+ assertNotNull(repMembers);
+ assertEquals(SIZE_TH, repMembers.count());
+
+ // the members-list must how have two ref-members nodes one with 10 and
+ // one with a single ref-value
+ assertMemberList(groupTree, 2, 1);
+
+ // 2. add more members without reaching threshold => still 2 ref-nodes
+ memberIds = createIdMap(21, 29);
+ mp.addMembers(groupTree, memberIds);
+ assertMemberList(groupTree, 2, 9);
+
+ // 3. fill up second ref-members node => a new one must be created
+ memberIds = createIdMap(29, 35);
+ mp.addMembers(groupTree, memberIds);
+ assertMemberList(groupTree, 3, 5);
+
+ // 4. remove members from the initial set => ref nodes as before, rep:members prop on group modified
+ memberIds.clear();
+ memberIds.put(MembershipProvider.getContentID("member1"), "member1");
+ memberIds.put(MembershipProvider.getContentID("member2"), "member2");
+ mp.removeMembers(groupTree, Maps.newHashMap(memberIds));
+
+ assertMemberList(groupTree, 3, 5);
+ assertEquals(8, groupTree.getProperty(REP_MEMBERS).count());
+
+ // 5. add members again => best-tree is the ref-member-node
+ memberIds = createIdMap(35, 39);
+ mp.addMembers(groupTree, memberIds);
+
+ assertEquals(8, groupTree.getProperty(REP_MEMBERS).count());
+ assertMemberList(groupTree, 3, 9);
+
+ // 6. adding more members will fill up rep:members again and create new ref-node
+ memberIds = createIdMap(39, 45);
+ mp.addMembers(groupTree, memberIds);
+
+ assertEquals(SIZE_TH, groupTree.getProperty(REP_MEMBERS).count());
+ assertEquals(4, groupTree.getChild(REP_MEMBERS_LIST).getChildrenCount(10));
+ }
+
private User createUser() throws RepositoryException {
String userId = "testUser" + testUsers.size();
User usr = userMgr.createUser(userId, "pw");
- testUsers.add(userId);
- if ((testUsers.size() + testGroups.size()) % 100 == 0) {
- System.out.println("created " + testGroups.size() + " groups, " + testUsers.size() + " users.");
- }
+ testUsers.add(usr.getPath());
return usr;
}
private Group createGroup() throws RepositoryException {
String groupName = "testGroup" + testGroups.size();
Group grp = userMgr.createGroup(groupName);
- testGroups.add(groupName);
- if ((testUsers.size() + testGroups.size()) % 100 == 0) {
- System.out.println("created " + testGroups.size() + " groups, " + testUsers.size() + " users.");
- }
+ testGroups.add(grp.getPath());
return grp;
}
- private void checkMembers(Group grp, Set<String> ms) throws RepositoryException {
+ private List<Authorizable> createMembers(@Nonnull Group g, int cnt) throws Exception {
+ List<Authorizable> members = new ArrayList();
+ for (int i = 0; i <= cnt; i++) {
+ User u = createUser();
+ Group gr = createGroup();
+ g.addMembers(u.getID(), gr.getID());
+ members.add(u);
+ members.add(gr);
+ }
+ return members;
+ }
+
+ private static Map<String, String> createIdMap(int start, int end) {
+ Map<String, String> memberIds = Maps.newLinkedHashMap();
+ for (int i = start; i < end; i++) {
+ String memberId = "member" + i;
+ memberIds.put(MembershipProvider.getContentID(memberId), memberId);
+ }
+ return memberIds;
+ }
+
+ private static void assertMembers(Group grp, Set<String> ms) throws RepositoryException {
Set<String> members = new HashSet<String>(ms);
Iterator<Authorizable> iter = grp.getMembers();
while (iter.hasNext()) {
@@ -355,4 +584,19 @@ public class MembershipProviderTest exte
}
assertEquals("Group must have all members", 0, members.size());
}
+
+ private static void assertMemberList(@Nonnull Tree groupTree, int cntRefTrees, int cnt) {
+ Tree list = groupTree.getChild(REP_MEMBERS_LIST);
+ assertTrue(list.exists());
+ assertEquals(cntRefTrees, list.getChildrenCount(5));
+ for (Tree c : list.getChildren()) {
+ PropertyState repMembers = c.getProperty(REP_MEMBERS);
+ assertNotNull(repMembers);
+ assertTrue(SIZE_TH == repMembers.count() || cnt == repMembers.count());
+ }
+ }
+
+ private Tree getTree(@Nonnull Authorizable a) throws Exception {
+ return root.getTree(a.getPath());
+ }
}
\ No newline at end of file
Copied: jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RemoveMembersByIdBestEffortTest.java (from r1694049, jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RemoveMembersByIdBestEffortTest.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RemoveMembersByIdBestEffortTest.java?p2=jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RemoveMembersByIdBestEffortTest.java&p1=jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RemoveMembersByIdBestEffortTest.java&r1=1694049&r2=1756639&rev=1756639&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RemoveMembersByIdBestEffortTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/RemoveMembersByIdBestEffortTest.java Wed Aug 17 14:21:07 2016
@@ -62,4 +62,20 @@ public class RemoveMembersByIdBestEffort
root.refresh();
assertFalse(testGroup.isMember(memberGroup));
}
+
+ @Test
+ public void testMemberListExistingMembers() throws Exception {
+ MembershipProvider mp = ((UserManagerImpl) getUserManager(root)).getMembershipProvider();
+ try {
+ mp.setMembershipSizeThreshold(5);
+ for (int i = 0; i < 10; i++) {
+ testGroup.addMembers("member" + i);
+ }
+
+ Set<String> failed = testGroup.removeMembers("member8");
+ assertTrue(failed.isEmpty());
+ } finally {
+ mp.setMembershipSizeThreshold(100); // back to default
+ }
+ }
}
\ No newline at end of file
Modified: jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserInitializerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserInitializerTest.java?rev=1756639&r1=1756638&r2=1756639&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserInitializerTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserInitializerTest.java Wed Aug 17 14:21:07 2016
@@ -130,6 +130,13 @@ public class UserInitializerTest extends
assertArrayEquals(
new String[]{UserConstants.NT_REP_AUTHORIZABLE},
Iterables.toArray(declaringNtNames, String.class));
+
+ Tree repMembers = oakIndex.getChild("repMembers");
+ assertIndexDefinition(repMembers, UserConstants.REP_MEMBERS, false);
+ declaringNtNames = TreeUtil.getStrings(repMembers, IndexConstants.DECLARING_NODE_TYPES);
+ assertArrayEquals(
+ new String[]{UserConstants.NT_REP_MEMBER_REFERENCES},
+ Iterables.toArray(declaringNtNames, String.class));
}
/**
Modified: jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserValidatorTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserValidatorTest.java?rev=1756639&r1=1756638&r2=1756639&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserValidatorTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserValidatorTest.java Wed Aug 17 14:21:07 2016
@@ -48,7 +48,6 @@ import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
@@ -320,9 +319,41 @@ public class UserValidatorTest extends A
group1.addMember(group2);
group2.addMember(group3);
-
- assertFalse(group3.addMember(group1));
-
+
+ // manually create the cyclic membership
+ Tree group3Tree = root.getTree(group3.getPath());
+ Set<String> values = Collections.singleton(root.getTree(group1.getPath()).getProperty(JcrConstants.JCR_UUID).getValue(Type.STRING));
+ PropertyState prop = PropertyStates.createProperty(REP_MEMBERS, values, Type.WEAKREFERENCES);
+ group3Tree.setProperty(prop);
+ root.commit();
+ fail("Cyclic group membership must be detected");
+ } catch (CommitFailedException e) {
+ // success
+ } finally {
+ if (group1 != null) group1.remove();
+ if (group2 != null) group2.remove();
+ if (group3 != null) group3.remove();
+ root.commit();
+ }
+ }
+
+ @Test
+ public void testDetectCyclicMembershipWithIntermediateCommit() throws Exception {
+ Group group1 = null;
+ Group group2 = null;
+ Group group3 = null;
+
+ UserManager userMgr = getUserManager(root);
+ try {
+ group1 = userMgr.createGroup("group1");
+ group2 = userMgr.createGroup("group2");
+ group3 = userMgr.createGroup("group3");
+
+ group1.addMember(group2);
+ group2.addMember(group3);
+ root.commit();
+
+ // manually create the cyclic membership
Tree group3Tree = root.getTree(group3.getPath());
Set<String> values = Collections.singleton(root.getTree(group1.getPath()).getProperty(JcrConstants.JCR_UUID).getValue(Type.STRING));
PropertyState prop = PropertyStates.createProperty(REP_MEMBERS, values, Type.WEAKREFERENCES);
Modified: jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/autosave/AutoSaveEnabledManagerTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/autosave/AutoSaveEnabledManagerTest.java?rev=1756639&r1=1756638&r2=1756639&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/autosave/AutoSaveEnabledManagerTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/autosave/AutoSaveEnabledManagerTest.java Wed Aug 17 14:21:07 2016
@@ -248,4 +248,23 @@ public class AutoSaveEnabledManagerTest
assertFalse(root.hasPendingChanges());
assertFalse(u.declaredMemberOf().hasNext());
}
+
+ @Test
+ public void testAddMembers() throws Exception {
+ User u = mgr.createUser("u", "u");
+ Group g = mgr.createGroup("g");
+
+ assertTrue(g.addMembers(u.getID()).isEmpty());
+ assertFalse(root.hasPendingChanges());
+ }
+
+ @Test
+ public void testRemoveMembers() throws Exception {
+ User u = mgr.createUser("u", "u");
+ Group g = mgr.createGroup("g");
+ g.addMember(u);
+
+ assertTrue(g.removeMembers(u.getID()).isEmpty());
+ assertFalse(root.hasPendingChanges());
+ }
}
\ No newline at end of file
Copied: jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/GroupActionBestEffortTest.java (from r1735564, jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/GroupActionBestEffortTest.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/GroupActionBestEffortTest.java?p2=jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/GroupActionBestEffortTest.java&p1=jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/GroupActionBestEffortTest.java&r1=1735564&r2=1756639&rev=1756639&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/GroupActionBestEffortTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/GroupActionBestEffortTest.java Wed Aug 17 14:21:07 2016
@@ -16,13 +16,14 @@
*/
package org.apache.jackrabbit.oak.spi.security.user.action;
-import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import org.apache.jackrabbit.oak.spi.xml.ImportBehavior;
import org.junit.Test;
-import java.util.List;
+import java.util.Set;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -30,7 +31,7 @@ public class GroupActionBestEffortTest e
@Test
public void testMembersAddedNonExisting() throws Exception {
- List<String> nonExisting = ImmutableList.of("blinder", "passagier");
+ Set<String> nonExisting = ImmutableSet.of("blinder", "passagier");
testGroup.addMembers(nonExisting.toArray(new String[nonExisting.size()]));
assertTrue(Iterables.elementsEqual(nonExisting, groupAction.memberIds));
@@ -39,11 +40,11 @@ public class GroupActionBestEffortTest e
@Test
public void testMembersRemovedNonExisting() throws Exception {
- List<String> nonExisting = ImmutableList.of("blinder", "passagier");
+ Set<String> nonExisting = ImmutableSet.of("blinder", "passagier");
testGroup.removeMembers(nonExisting.toArray(new String[nonExisting.size()]));
assertFalse(groupAction.memberIds.iterator().hasNext());
- assertTrue(Iterables.elementsEqual(nonExisting, groupAction.failedIds));
+ assertEquals(nonExisting, groupAction.failedIds);
}
@Override
Copied: jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/GroupActionTest.java (from r1735564, jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/GroupActionTest.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/GroupActionTest.java?p2=jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/GroupActionTest.java&p1=jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/GroupActionTest.java&r1=1735564&r2=1756639&rev=1756639&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/GroupActionTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/GroupActionTest.java Wed Aug 17 14:21:07 2016
@@ -17,6 +17,7 @@
package org.apache.jackrabbit.oak.spi.security.user.action;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.Group;
@@ -41,6 +42,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.jcr.RepositoryException;
import java.util.List;
+import java.util.Set;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -113,20 +115,20 @@ public class GroupActionTest extends Abs
testUser02 = getUserManager(root).createUser(TEST_USER_PREFIX + "02", "");
testGroup.addMember(testUser02);
- List<String> memberIds = ImmutableList.of(testUser01.getID());
- List<String> failedIds = ImmutableList.of(testUser02.getID(), testGroup.getID());
+ Set<String> memberIds = ImmutableSet.of(testUser01.getID());
+ Set<String> failedIds = ImmutableSet.of(testUser02.getID(), testGroup.getID());
Iterable<String> ids = Iterables.concat(memberIds, failedIds);
testGroup.addMembers(Iterables.toArray(ids, String.class));
assertTrue(groupAction.onMembersAddedCalled);
assertEquals(testGroup, groupAction.group);
- assertTrue(Iterables.elementsEqual(memberIds, groupAction.memberIds));
- assertTrue(Iterables.elementsEqual(failedIds, groupAction.failedIds));
+ assertEquals(memberIds, groupAction.memberIds);
+ assertEquals(failedIds, groupAction.failedIds);
}
@Test
public void testMembersAddedNonExisting() throws Exception {
- List<String> nonExisting = ImmutableList.of("blinder", "passagier");
+ Set<String> nonExisting = ImmutableSet.of("blinder", "passagier");
testGroup.addMembers(nonExisting.toArray(new String[nonExisting.size()]));
assertFalse(groupAction.memberIds.iterator().hasNext());
@@ -139,20 +141,20 @@ public class GroupActionTest extends Abs
testUser02 = getUserManager(root).createUser(TEST_USER_PREFIX + "02", "");
testGroup.addMember(testUser01);
- List<String> memberIds = ImmutableList.of(testUser01.getID());
- List<String> failedIds = ImmutableList.of(testUser02.getID(), testGroup.getID());
+ Set<String> memberIds = ImmutableSet.of(testUser01.getID());
+ Set<String> failedIds = ImmutableSet.of(testUser02.getID(), testGroup.getID());
Iterable<String> ids = Iterables.concat(memberIds, failedIds);
testGroup.removeMembers(Iterables.toArray(ids, String.class));
assertTrue(groupAction.onMembersRemovedCalled);
assertEquals(testGroup, groupAction.group);
- assertTrue(Iterables.elementsEqual(memberIds, groupAction.memberIds));
- assertTrue(Iterables.elementsEqual(failedIds, groupAction.failedIds));
+ assertEquals(memberIds, groupAction.memberIds);
+ assertEquals(failedIds, groupAction.failedIds);
}
@Test
public void testMembersRemovedNonExisting() throws Exception {
- List<String> nonExisting = ImmutableList.of("blinder", "passagier");
+ Set<String> nonExisting = ImmutableSet.of("blinder", "passagier");
testGroup.removeMembers(nonExisting.toArray(new String[nonExisting.size()]));
assertFalse(groupAction.memberIds.iterator().hasNext());
@@ -175,8 +177,8 @@ public class GroupActionTest extends Abs
boolean onMembersRemovedCalled = false;
Group group;
- Iterable<String> memberIds;
- Iterable<String> failedIds;
+ Set<String> memberIds;
+ Set<String> failedIds;
Authorizable member;
@Override
@@ -189,8 +191,8 @@ public class GroupActionTest extends Abs
@Override
public void onMembersAdded(@Nonnull Group group, @Nonnull Iterable<String> memberIds, @Nonnull Iterable<String> failedIds, @Nonnull Root root, @Nonnull NamePathMapper namePathMapper) throws RepositoryException {
this.group = group;
- this.memberIds = memberIds;
- this.failedIds = failedIds;
+ this.memberIds = ImmutableSet.copyOf(memberIds);
+ this.failedIds = ImmutableSet.copyOf(failedIds);
onMembersAddedCalled = true;
}
@@ -204,8 +206,8 @@ public class GroupActionTest extends Abs
@Override
public void onMembersRemoved(@Nonnull Group group, @Nonnull Iterable<String> memberIds, @Nonnull Iterable<String> failedIds, @Nonnull Root root, @Nonnull NamePathMapper namePathMapper) throws RepositoryException {
this.group = group;
- this.memberIds = memberIds;
- this.failedIds = failedIds;
+ this.memberIds = ImmutableSet.copyOf(memberIds);
+ this.failedIds = ImmutableSet.copyOf(failedIds);
onMembersRemovedCalled = true;
}
}
Modified: jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordValidationActionTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordValidationActionTest.java?rev=1756639&r1=1756638&r2=1756639&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordValidationActionTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/spi/security/user/action/PasswordValidationActionTest.java Wed Aug 17 14:21:07 2016
@@ -33,6 +33,7 @@ import org.apache.jackrabbit.oak.securit
import org.apache.jackrabbit.oak.security.user.UserConfigurationImpl;
import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
import org.apache.jackrabbit.oak.spi.security.SecurityProvider;
+import org.apache.jackrabbit.oak.spi.security.principal.PrincipalProvider;
import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration;
import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
import org.apache.jackrabbit.oak.spi.security.user.util.PasswordUtil;
@@ -200,6 +201,12 @@ public class PasswordValidationActionTes
return ConfigurationParameters.of(super.getParameters(),
ConfigurationParameters.of(UserConstants.PARAM_AUTHORIZABLE_ACTION_PROVIDER, actionProvider));
}
+
+ @Nullable
+ @Override
+ public PrincipalProvider getUserPrincipalProvider(@Nonnull Root root, @Nonnull NamePathMapper namePathMapper) {
+ return null;
+ }
};
} else {
return super.getConfiguration(configClass);
Modified: jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/user.md
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/user.md?rev=1756639&r1=1756638&r2=1756639&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/user.md (original)
+++ jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/user.md Wed Aug 17 14:21:07 2016
@@ -18,14 +18,16 @@
User Management
--------------------------------------------------------------------------------
-### JCR User Management
+<a href="jcr_api"/>
+### JCR API
JCR itself doesn't come with a dedicated user management API. The only method
related and ultimately used for user management tasks is `Session.getUserID()`.
Therefore an API for user and group management has been defined as part of the
extensions present with Jackrabbit API.
-### Jackrabbit User Management API
+<a name="jackrabbit_api"/>
+### Jackrabbit API
The Jackrabbit API provides the user management related extensions that are
missing in JCR. The relevant interfaces are defined in the
@@ -39,214 +41,26 @@ missing in JCR. The relevant interfaces
- `QueryBuilder`
- `Query`
-### Oak User Management Implementation
-
-The default user management implementation stores user/group information in the
-content repository. In contrast to Jackrabbit 2.x, which by default used a single,
-dedicated workspace for user/group data, this data will as of Oak 1.0 be stored
-separately for each JCR workspace.
-
-Consequently the `UserManager` associated with the editing sessions, performs
-all actions with this editing session. This corresponds to the behavior as defined
-the alternative implementation present with Jackrabbit 2.x ((see Jackrabbit 2.x `UserPerWorkspaceUserManager`).
-
-#### General
-* The Oak implementation is build on the Oak API. This allows for double usage as
- extension to the JCR API as well as within the Oak layer (aka SPI).
-* The `UserManager` is always associated with the same JCR workspace as the editing
- `Session` from which the class has been obtained.
-* Changes made to the user management API are always transient and require `Session#save()` to be persisted.
-* In case of any failure during user management related write operations the API
- consumer is in charge of specifically revert pending or invalid transient modifications
- or calling `Session#refresh(false)`.
-
-#### Differences wrt Jackrabbit 2.x
-
-A summary of all changes with respect to the former implementation present with
-Jackrabbit 2.x is present in the corresponding [section](user/differences.html).
-
-#### Built-in Users and Special Groups
-
-The setup of builtin user and group accounts is triggered by the configured `WorkspaceInitializer`
-associated with the user management configuration (see Configuration section below).
-
-The default user management implementation in OAK comes with an initializer that
-creates the following builtin user accounts:
-
-##### Administrator
-The admin user is always being created. The ID of this user is retrieved from the
-user configuration parameter `PARAM_ADMIN_ID`, which defaults to `admin`.
-
-As of OAK 1.0 however the administrator user might be created without initial
-password forcing the application to set the password upon start (see `PARAM_OMIT_ADMIN_PW`
-configuration parameter).
-
-##### Anonymous User
-In contrast to Jackrabbit 2.x the anonymous (or guest) user is optional. Creation
-will be skipped if the value of the `PARAM_ANONYMOUS_ID` configuration parameter
-is `null` or empty.
-
-Note, that the anonymous user will always be created without specifying a password
-in order to prevent regular login with `SimpleCredentials`.
-The proper way to obtain a guest session is:
-
- Repository#login(new GuestCredentials(), wspName);
-
-See section [Authentication](authentication.html) for further information about
-guest login.
-
-##### Everyone Group
-
-The default user management implementation in Oak contains special handling for
-the optional group that represents _everyone_, which is marked by the reserved
-name [everyone] and corresponds to the `EveryonePrincipal`.
-
-This special group always contains all Authorizable as member and cannot be edited
-with user management API. As of OAK this fact is consistently reflected in all
-group membership related methods. See also [Principal Management](principal.html).
-
-#### Reading Authorizables
-
-##### Handling of the Authorizable ID
-* As of Oak the node type definition of `rep:Authorizable` defines a new property `rep:authorizableId` which is intended to store the ID of a user or group.
-* The default implementation comes with a dedicated property index for `rep:authorizableId` which asserts the uniqueness of that ID.
-* `Authorizable#getID` returns the string value contained in `rep:authorizableID` and for backwards compatibility falls back on the node name in case the ID property is missing.
-* The name of the authorizable node is generated based on a configurable implementation of the `AuthorizableNodeName` interface (see configuration section below). By default it uses the ID as name hint and includes a conversion to a valid JCR node name.
-
-##### equals() and hashCode()
-The implementation of `Object#equals()` and `Object#hashCode()` for user and
-groups slightly differs from Jackrabbit 2.x. It no longer relies on the _sameness_
-of the underlaying JCR node but only compares IDs and the user manager instance.
-
-#### Creating Authorizables
-* The `rep:password` property is no longer defined to be mandatory. Therefore a new user might be created without specifying a password. Note however, that `User#changePassword` does not allow to remove the password property.
-* `UserManager#createGroup(Principal)` will no longer generate a groupID in case the principal name collides with an existing user or group ID. This has been considered redundant as the Jackrabbit API in the mean time added `UserManager#createGroup(String groupID)`.
-* Since OAK is designed to scale with flat hierarchies the former configuration options `autoExpandTree` and `autoExpandSize` are no longer supported.
-
-#### Query
-
-See section [Searching Users and Groups](user/query.html) for details.
-
-#### Group Membership
-
-See section [Group Membership](user/membership.html) for details.
-
-#### Autosave Behavior
-Due to the nature of the UserManager (see above) we decided to drop the auto-save
-behavior in the default implementation present with OAK. Consequently,
-
-* `UserManager#autoSave(boolean)` throws `UnsupportedRepositoryOperationException`
-* `UserManager#isAutoSave()` always returns `false`
-
-See also `PARAM_SUPPORT_AUTOSAVE` below; while this should not be needed if
-application code has been written against the Jackrabbit API (and thus testing if
-auto-save mode is enabled or not) this configuration option can be used as last resort.
-
-
-#### User/Group Representation in the Repository
-
-The following block lists the built-in node types related to user management tasks:
-
- [rep:Authorizable] > mix:referenceable, nt:hierarchyNode
- abstract
- + * (nt:base) = nt:unstructured VERSION
- - rep:principalName (STRING) protected mandatory
- - rep:authorizableId (STRING) protected /* @since oak 1.0 */
- - * (UNDEFINED)
- - * (UNDEFINED) multiple
-
- [rep:Group] > rep:Authorizable, rep:MemberReferences
- + rep:members (rep:Members) = rep:Members multiple protected VERSION /* @deprecated */
- + rep:membersList (rep:MemberReferencesList) = rep:MemberReferencesList protected COPY
-
- /** @since oak 1.0 */
- [rep:MemberReferences]
- - rep:members (WEAKREFERENCE) protected multiple < 'rep:Authorizable'
-
- /** @since oak 1.0 */
- [rep:MemberReferencesList]
- + * (rep:MemberReferences) = rep:MemberReferences protected COPY
-
- /** @deprecated since oak 1.0 */
- [rep:Members]
- orderable
- + * (rep:Members) = rep:Members protected multiple
- - * (WEAKREFERENCE) protected < 'rep:Authorizable'
-
-<a name="validation"/>
-##### Validation
-
-The consistency of this content structure is asserted by a dedicated `UserValidator`.
-The corresponding errors are all of type `Constraint` with the following codes:
-
-| Code | Message |
-|-------------------|----------------------------------------------------------|
-| 0020 | Admin user cannot be disabled |
-| 0021 | Invalid jcr:uuid for authorizable (creation) |
-| 0022 | Changing Id, principal name after creation |
-| 0023 | Invalid jcr:uuid for authorizable (mod) |
-| 0024 | Password may not be plain text |
-| 0025 | Attempt to remove id, principalname or pw |
-| 0026 | Mandatory property rep:principalName missing |
-| 0027 | The admin user cannot be removed |
-| 0028 | Attempt to create outside of configured scope |
-| 0029 | Intermediate folders not rep:AuthorizableFolder |
-| 0030 | Missing uuid for group (check for cyclic membership) |
-| 0031 | Cyclic group membership |
-| 0032 | Attempt to set password with system user |
-| 0033 | Attempt to add rep:pwd node to a system user |
-
-
-#### XML Import
-As of Oak 1.0 user and group nodes can be imported both with Session and Workspace
-import. Other differences compared to Jackrabbit 2.x:
-
-* Importing an authorizable to another tree than the configured user/group node will only failed upon save (-> see `UserValidator` during the `Root#commit`). With Jackrabbit 2.x core it used to fail immediately.
-* The `BestEffort` behavior is now also implemented for the import of impersonators (was missing in Jackrabbit /2.x).
-
+<a name="api_extensions"/>
### API Extensions
+
The Oak project introduces the following user management related public
interfaces and classes:
-#### Authorizable Actions
-
-The former internal Jackrabbit interface `AuthorizableAction` has been slightly
-adjusted to match Oak requirements and is now part of the public Oak SPI interfaces.
-In contrast to Jackrabbit-core the AuthorizableAction(s) now operate directly on
-the Oak API, which eases the handling of implementation specific tasks such as
-writing protected items.
-
-See section [Authorizable Actions](user/authorizableaction.html) for further
-details and examples.
-
-#### Node Name Generation
-
-The default user management implementation with Oak 1.0 allows to specify how
-the name of a new authorizable node is being generated.
-
-See section [Authorizable Node Name](user/authorizablenodename.html) for further
-details and examples.
-
-#### Password Expiry and Force Initial Password Change
+- `AuthorizableType`: ease handling with the different authorizable types.
+- `AuthorizableAction` and `AuthorizableActionProvider`: see [Authorizable Actions](user/authorizableaction.html) for details.
+- `AuthorizableNodeName`: see section [Authorizable Node Name Generation](user/authorizablenodename.html).
+- `GroupAction` (via `AuthorizableActionProvider`): see [Group Actions](user/groupaction.html) for details.
+- `UserAuthenticationFactory`: see sections [pluggability](user/default.html#pluggability)
+and [user authentication](authentication/default.html#user_authentication) for additional details.
-Since Oak 1.1.0 the default user management and authentication implementation
-provides password expiry and initial password change.
-
-By default these features are disabled. The corresponding configuration options
-are
-
-- `PARAM_PASSWORD_MAX_AGE`: number of days until the password expires.
-- `PARAM_PASSWORD_INITIAL_CHANGE`: boolean flag to enable this feature.
-
-See section [Password Expiry and Force Initial Password Change](user/expiry.html)
-for details.
-
-#### Utilities
+<a href="utilities"/>
+### Utilities
`org.apache.jackrabbit.oak.spi.security.user.*`
-- `AuthorizableType` : Ease handling with the different authorizable types.
- `UserConstants` : Constants (NOTE: OAK names/paths)
+- `UserIdCredentials` : Simple credentials implementation that might be used for `User.getCredentials' without exposing pw information.
`org.apache.jackrabbit.oak.spi.security.user.util.*`
@@ -256,74 +70,53 @@ for details.
function for password generation.
- `UserUtil` : Utilities related to general user management tasks.
+<a href="default_implementation"/>
+### Oak User Management Implementation
+
+The behavior of the default user management implementation is described in section
+[User Management: The Default Implementation](user/default.html).
+<a name="configuration"/>
### Configuration
-The following user management specific methods are present with the [UserConfiguration]
-as of OAK 1.0:
+The Oak user management comes with a dedicated entry point called [UserConfiguration].
+This class is responsible for passing configuration options to the implementation
+and provides the following two methods:
-* getUserManager: Obtain a new user manager instance
+- `getUserManager(Root, NamePathMapper)`: get a new `UserManager` instance
+- `getUserPrincipalProvider(Root, NamePathMapper)`: optional method that allows for optimized principal look-up from user/group accounts (since Oak 1.3.4).
-#### Configuration Parameters supported by the default implementation
+#### Configuration Parameters
-| Parameter | Type | Default |
-|-------------------------------------|---------|----------------------------------------------|
-| `PARAM_ADMIN_ID` | String | "admin" |
-| `PARAM_OMIT_ADMIN_PW` | boolean | false |
-| `PARAM_ANONYMOUS_ID` | String | "anonymous" (nullable) |
-| `PARAM_USER_PATH` | String | "/rep:security/rep:authorizables/rep:users" |
-| `PARAM_GROUP_PATH` | String | "/rep:security/rep:authorizables/rep:groups" |
-| `PARAM_DEFAULT_DEPTH` | int | 2 |
-| `PARAM_PASSWORD_HASH_ALGORITHM` | String | "SHA-256" |
-| `PARAM_PASSWORD_HASH_ITERATIONS` | int | 1000 |
-| `PARAM_PASSWORD_SALT_SIZE` | int | 8 |
-| `PARAM_AUTHORIZABLE_NODE_NAME` | AuthorizableNodeName | AuthorizableNodeName#DEFAULT |
-| `PARAM_AUTHORIZABLE_ACTION_PROVIDER`| AuthorizableActionProvider | DefaultAuthorizableActionProvider |
-| `PARAM_SUPPORT_AUTOSAVE` | boolean | false |
-| `PARAM_IMPORT_BEHAVIOR` | String ("abort", "ignore", "besteffort") | "ignore" |
-| `PARAM_PASSWORD_MAX_AGE` | int | 0 |
-| `PARAM_PASSWORD_INITIAL_CHANGE` | boolean | false |
-| | | |
-
-The following configuration parameters present with the default implementation in Jackrabbit 2.x are no longer supported and will be ignored:
-
-* 'compatibleJR16'
-* 'autoExpandTree'
-* 'autoExpandSize'
-* 'groupMembershipSplitSize'
+The supported configuration options of the default implementation are described in the corresponding [section](user/default.html#configuration).
+<a name="pluggability"/>
### Pluggability
-The default security setup as present with Oak 1.0 is able to provide custom
-implementation on various levels:
+The default security setup as present with Oak 1.0 is able to have the default
+user management implementation replaced as follows:
-1. The complete user management implementation can be changed by plugging a different
- `UserConfiguration` implementations. In OSGi-base setup this is achieved by making
- the configuration a service. In a non-OSGi-base setup the custom configuration
- must be exposed by the `SecurityProvider` implementation.
-2. Within the default user management implementation the following parts can be
- change/extended at runtime by providing corresponding OSGi services or passing
- appropriate configuration parameters exposing the custom implementations:
- - `AuthorizableActionProvider`: Defines the authorizable actions, see [Authorizable Actions](user/authorizableaction.html).
- - `AuthorizableNodeName`: Defines the generation of the authorizable node names
- in case the user management implementation stores user information in the repository.
- See [Authorizable Node Name Generation](user/authorizablenodename.html).
+The complete user management implementation can be changed by plugging a different
+`UserConfiguration` implementations. In OSGi-base setup this is achieved by making
+the configuration a service which must take precedence over the default.
+In a non-OSGi-base setup the custom configuration must be exposed by the
+`SecurityProvider` implementation.
+
+Alternatively the default user management implementation can be extended and
+adjusted using various means. See the corresponding [section](user/default.html#pluggability)
+for further details.
+<a name="further_reading"/>
### Further Reading
- [Differences wrt Jackrabbit 2.x](user/differences.html)
-- [Group Membership](user/membership.html)
-- [Authorizable Actions](user/authorizableaction.html)
-- [Authorizable Node Name](user/authorizablenodename.html)
+- [User Management : The Default Implementation](user/default.html)
+ - [Group Membership](user/membership.html)
+ - [Authorizable Actions](user/authorizableaction.html)
+ - [Authorizable Node Name](user/authorizablenodename.html)
+ - [Password Expiry and Force Initial Password Change](user/expiry.html)
+ - [Password History](user/history.html)
- [Searching Users and Groups](user/query.html)
-- [Password Expiry and Force Initial Password Change](user/expiry.html)
<!-- hidden references -->
-[everyone]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/principal/EveryonePrincipal.html#NAME
[UserConfiguration]: /oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/user/UserConfiguration.html
-[OAK-118]: https://issues.apache.org/jira/browse/OAK-118
-[OAK-482]: https://issues.apache.org/jira/browse/OAK-482
-[OAK-793]: https://issues.apache.org/jira/browse/OAK-793
-[OAK-949]: https://issues.apache.org/jira/browse/OAK-949
-[OAK-1183]: https://issues.apache.org/jira/browse/OAK-1183
-
Modified: jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/user/membership.md
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/user/membership.md?rev=1756639&r1=1756638&r2=1756639&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/user/membership.md (original)
+++ jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/user/membership.md Wed Aug 17 14:21:07 2016
@@ -30,6 +30,8 @@ member relationship of users and groups:
- `isMember(Authorizable boolean`
- `addMember(Authorizable) boolean`
- `removeMember(Authorizable) boolen`
+ - `addMembers(String...) Set<String>`
+ - `removeMembers(String...) Set<String>`
- [org.apache.jackrabbit.api.security.user.Authorizable]
- `declaredMemberOf() Iterator<Group>`
@@ -139,6 +141,29 @@ internally processed using the normal us
node structure after the import might not be the same as the one represented in
the input.
+#### Add and Remove Group Members by Id
+
+Since Oak 1.3.4 the default user management implementation also allows to modify
+group membership by specifying the member id(s) (see [JCR-3880] and [OAK-3170]).
+The following details are worth mentioning:
+
+- a `null` or empty String id will immediately fail the operation with `ConstraintViolationException`; changes already made will not be reverted,
+- an attemt to make the same group member of itself will list that id in the return value but will not fail the operation,
+- duplicate ids in the parameter list will be silently ignored,
+- cyclic membership validation is postponed to the validator called upon `Root.commit`
+ and will only fail at that point; the cyclic membership then needs to be manually
+ resolved by the application,
+- whether or not a non-existing (or not accessible) authorizable can be added or
+ removed depends on the configured `ImportBehavior`:
+ - ABORT: each id is resolved to the corresponding authorizable; if it doesn't
+ exist `ConstraintViolationException` is thrown immediately; changes already
+ made will not be reverted.
+ - BESTEFFORT: the specified ids are not resolved to the corresponding
+ authorizables and are silently added|removed to|from the set of members;
+ ids that were not successfully added|removed are listed in the return value.
+ - IGNORE: each id is resolved to the corresponding authorizable; if it doesn't
+ exist it will be returned as _failed_ in the return value.
+
### Configuration
Note that as of Oak 1.0 the implementation is responsible for defining the
@@ -149,4 +174,6 @@ with Jackrabbit 2.x is not supported any
<!-- hidden references -->
[org.apache.jackrabbit.api.security.user.Group]: http://svn.apache.org/repos/asf/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Group.java
-[org.apache.jackrabbit.api.security.user.Authorizable]: http://svn.apache.org/repos/asf/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Authorizable.java
\ No newline at end of file
+[org.apache.jackrabbit.api.security.user.Authorizable]: http://svn.apache.org/repos/asf/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/security/user/Authorizable.java
+[JCR-3880]: https://issues.apache.org/jira/browse/JCR-3880
+[OAK-3170]: https://issues.apache.org/jira/browse/OAK-3170
Modified: jackrabbit/oak/branches/1.2/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/GroupDelegator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/GroupDelegator.java?rev=1756639&r1=1756638&r2=1756639&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/GroupDelegator.java (original)
+++ jackrabbit/oak/branches/1.2/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/delegate/GroupDelegator.java Wed Aug 17 14:21:07 2016
@@ -20,6 +20,7 @@
package org.apache.jackrabbit.oak.jcr.delegate;
import java.util.Iterator;
+import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.jcr.RepositoryException;
@@ -134,6 +135,17 @@ final class GroupDelegator extends Autho
}
@Override
+ public Set<String> addMembers(@Nonnull final String... memberIds) throws RepositoryException {
+ return sessionDelegate.perform(new SessionOperation<Set<String>>("addMembers") {
+ @Nonnull
+ @Override
+ public Set<String> perform() throws RepositoryException {
+ return getDelegate().addMembers(memberIds);
+ }
+ });
+ }
+
+ @Override
public boolean removeMember(final Authorizable authorizable) throws RepositoryException {
return sessionDelegate.perform(new SessionOperation<Boolean>("removeMember") {
@Nonnull
@@ -143,4 +155,15 @@ final class GroupDelegator extends Autho
}
});
}
+
+ @Override
+ public Set<String> removeMembers(@Nonnull final String... memberIds) throws RepositoryException {
+ return sessionDelegate.perform(new SessionOperation<Set<String>>("removeMembers") {
+ @Nonnull
+ @Override
+ public Set<String> perform() throws RepositoryException {
+ return getDelegate().removeMembers(memberIds);
+ }
+ });
+ }
}
Modified: jackrabbit/oak/branches/1.2/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionImpl.java?rev=1756639&r1=1756638&r2=1756639&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionImpl.java (original)
+++ jackrabbit/oak/branches/1.2/oak-jcr/src/main/java/org/apache/jackrabbit/oak/jcr/session/SessionImpl.java Wed Aug 17 14:21:07 2016
@@ -69,6 +69,7 @@ import org.apache.jackrabbit.oak.jcr.ses
import org.apache.jackrabbit.oak.jcr.xml.ImportHandler;
import org.apache.jackrabbit.oak.spi.security.authentication.ImpersonationCredentials;
import org.apache.jackrabbit.oak.spi.security.authorization.permission.Permissions;
+import org.apache.jackrabbit.util.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.ContentHandler;
@@ -745,6 +746,11 @@ public class SessionImpl implements Jack
//--------------------------------------------------< JackrabbitSession >---
@Override
+ public boolean hasPermission(String absPath, String... actions) throws RepositoryException {
+ return hasPermission(absPath, Text.implode(actions, ","));
+ }
+
+ @Override
@Nonnull
public PrincipalManager getPrincipalManager() throws RepositoryException {
return sessionContext.getPrincipalManager();
Modified: jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/authorization/AbstractEvaluationTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/authorization/AbstractEvaluationTest.java?rev=1756639&r1=1756638&r2=1756639&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/authorization/AbstractEvaluationTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/authorization/AbstractEvaluationTest.java Wed Aug 17 14:21:07 2016
@@ -45,6 +45,7 @@ import org.apache.jackrabbit.api.securit
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.spi.security.principal.EveryonePrincipal;
import org.apache.jackrabbit.test.NotExecutableException;
import org.apache.jackrabbit.test.api.security.AbstractAccessControlTest;
import org.junit.After;
Modified: jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AbstractImportTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AbstractImportTest.java?rev=1756639&r1=1756638&r2=1756639&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AbstractImportTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AbstractImportTest.java Wed Aug 17 14:21:07 2016
@@ -18,7 +18,6 @@ package org.apache.jackrabbit.oak.jcr.se
import java.io.ByteArrayInputStream;
import java.io.InputStream;
-import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -48,7 +47,6 @@ import org.apache.jackrabbit.oak.spi.xml
import org.apache.jackrabbit.test.NotExecutableException;
import org.junit.After;
import org.junit.Before;
-import org.junit.Test;
import static org.apache.jackrabbit.oak.jcr.AbstractRepositoryTest.dispose;
import static org.junit.Assert.assertFalse;
@@ -155,8 +153,16 @@ public abstract class AbstractImportTest
protected abstract String getTargetPath();
+ protected Session getImportSession() {
+ return adminSession;
+ }
+
+ protected UserManager getUserManager() throws RepositoryException {
+ return ((JackrabbitSession) getImportSession()).getUserManager();
+ }
+
protected Node getTargetNode() throws RepositoryException {
- return adminSession.getNode(getTargetPath());
+ return getImportSession().getNode(getTargetPath());
}
protected String getExistingUUID() throws RepositoryException {
@@ -171,6 +177,10 @@ public abstract class AbstractImportTest
}
protected void doImport(String parentPath, String xml, int importUUIDBehavior) throws Exception {
+ doImport(getImportSession(), parentPath, xml, importUUIDBehavior);
+ }
+
+ protected void doImport(Session importSession, String parentPath, String xml, int importUUIDBehavior) throws Exception {
InputStream in;
if (xml.charAt(0) == '<') {
in = new ByteArrayInputStream(xml.getBytes());
@@ -182,7 +192,7 @@ public abstract class AbstractImportTest
in = getClass().getResourceAsStream(xml);
}
try {
- adminSession.importXML(parentPath, in, importUUIDBehavior);
+ importSession.importXML(parentPath, in, importUUIDBehavior);
} finally {
in.close();
}
@@ -196,24 +206,4 @@ public abstract class AbstractImportTest
assertFalse(potentialID.equals(session.getNode(member.getPath()).getIdentifier()));
}
}
-
- private String getTestXml() {
- StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
- for (StackTraceElement element : stackTraceElements) {
- try {
- Class<?> clazz = Class.forName(element.getClassName());
- for (Method method : clazz.getMethods()){
- if(method.getName().equals(element.getMethodName())){
- if (method.getAnnotation(Test.class) != null) {
- return clazz.getSimpleName() + "-" + method.getName() + ".xml";
- }
- }
-
- }
- } catch (Exception e) {
- // oops do something here
- }
- }
- throw new IllegalArgumentException("no import xml given.");
- }
}
Modified: jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImportAbortTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImportAbortTest.java?rev=1756639&r1=1756638&r2=1756639&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImportAbortTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImportAbortTest.java Wed Aug 17 14:21:07 2016
@@ -64,7 +64,7 @@ public class GroupImportAbortTest extend
} catch (RepositoryException e) {
// success as well
} finally {
- adminSession.refresh(false);
+ getImportSession().refresh(false);
}
}
}
Modified: jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImportBestEffortTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImportBestEffortTest.java?rev=1756639&r1=1756638&r2=1756639&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImportBestEffortTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImportBestEffortTest.java Wed Aug 17 14:21:07 2016
@@ -21,11 +21,14 @@ import java.util.List;
import java.util.UUID;
import javax.jcr.Node;
import javax.jcr.PropertyType;
+import javax.jcr.Session;
import javax.jcr.Value;
+import javax.jcr.nodetype.ConstraintViolationException;
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.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
import org.apache.jackrabbit.oak.spi.xml.ImportBehavior;
import org.apache.jackrabbit.test.NotExecutableException;
@@ -57,6 +60,7 @@ public class GroupImportBestEffortTest e
invalid.add(UUID.randomUUID().toString()); // random uuid
invalid.add(getExistingUUID()); // uuid of non-authorizable node
+ Session s = getImportSession();
for (String id : invalid) {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
"<sv:node sv:name=\"gFolder\" 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\">" +
@@ -70,11 +74,11 @@ public class GroupImportBestEffortTest e
try {
// BESTEFFORT behavior -> must import non-existing members.
doImport(getTargetPath(), xml);
- Authorizable a = userMgr.getAuthorizable("g1");
+ Authorizable a = getUserManager().getAuthorizable("g1");
if (a.isGroup()) {
// the rep:members property must contain the invalid value
boolean found = false;
- Node grNode = adminSession.getNode(a.getPath());
+ Node grNode = s.getNode(a.getPath());
for (Value memberValue : grNode.getProperty(UserConstants.REP_MEMBERS).getValues()) {
assertEquals(PropertyType.WEAKREFERENCE, memberValue.getType());
if (id.equals(memberValue.getString())) {
@@ -85,12 +89,12 @@ public class GroupImportBestEffortTest e
assertTrue("ImportBehavior.BESTEFFORT must import non-existing members.",found);
// declared members must not list the invalid entry.
- assertNotDeclaredMember((Group) a, id, adminSession);
+ assertNotDeclaredMember((Group) a, id, s);
} else {
fail("'g1' was not imported as Group.");
}
} finally {
- adminSession.refresh(false);
+ s.refresh(false);
}
}
}
@@ -100,7 +104,7 @@ public class GroupImportBestEffortTest e
String g1Id = "0120a4f9-196a-3f9e-b9f5-23f31f914da7";
String nonExistingId = "b2f5ff47-4366-31b6-a533-d8dc3614845d"; // groupId of 'g' group.
- if (userMgr.getAuthorizable("g") != null) {
+ if (getUserManager().getAuthorizable("g") != null) {
throw new NotExecutableException();
}
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
@@ -115,11 +119,11 @@ public class GroupImportBestEffortTest e
// BESTEFFORT behavior -> must import non-existing members.
doImport(getTargetPath(), xml);
- Authorizable g1 = userMgr.getAuthorizable("g1");
+ Authorizable g1 = getUserManager().getAuthorizable("g1");
if (g1.isGroup()) {
// the rep:members property must contain the invalid value
boolean found = false;
- Node grNode = adminSession.getNode(g1.getPath());
+ Node grNode = getImportSession().getNode(g1.getPath());
for (Value memberValue : grNode.getProperty(UserConstants.REP_MEMBERS).getValues()) {
assertEquals(PropertyType.WEAKREFERENCE, memberValue.getType());
if (nonExistingId.equals(memberValue.getString())) {
@@ -138,7 +142,7 @@ public class GroupImportBestEffortTest e
String g1Id = "0120a4f9-196a-3f9e-b9f5-23f31f914da7";
String nonExistingId = "b2f5ff47-4366-31b6-a533-d8dc3614845d"; // groupId of 'g' group.
- if (userMgr.getAuthorizable("g") != null) {
+ if (getUserManager().getAuthorizable("g") != null) {
throw new NotExecutableException();
}
@@ -168,18 +172,31 @@ public class GroupImportBestEffortTest e
membership references.
expected:
- group is imported
- - circular membership is ignored
+ - circular membership is ignored (OR fails upon save)
- g is member of g1
- - g1 isn't member of g
+ - g1 isn't member of g (circular membership detected) OR saving changes fails
*/
doImport(getTargetPath() + "/gFolder", xml2);
- Authorizable g = userMgr.getAuthorizable("g");
- assertNotNull(g);
- if (g.isGroup()) {
- assertNotDeclaredMember((Group) g, g1Id, adminSession);
+ Group g = getUserManager().getAuthorizable("g", Group.class);
+ Group g1 = getUserManager().getAuthorizable("g1", Group.class);
+
+ assertNotNull("'g' was not imported as Group.", g);
+ assertNotNull("'g1' was not imported as Group.", g1);
+
+ assertTrue(g1.isDeclaredMember(g));
+ if (g.isDeclaredMember(g1)) {
+ // circular membership created during import
+ try {
+ getImportSession().save();
+ fail("Circular membership must be detected upon save.");
+ } catch (ConstraintViolationException e) {
+ Throwable th = e.getCause();
+ assertTrue(th instanceof CommitFailedException);
+ assertEquals(31, ((CommitFailedException) th).getCode());
+ }
} else {
- fail("'g' was not imported as Group.");
+ assertNotDeclaredMember(g, g1Id, getImportSession());
}
}
@@ -199,10 +216,10 @@ public class GroupImportBestEffortTest e
"</sv:node>";
doImport(getTargetPath(), xml);
- User user = userMgr.createUser("angi", "pw");
- adminSession.save();
+ User user = getUserManager().createUser("angi", "pw");
+ getImportSession().save();
- Group g1 = (Group) userMgr.getAuthorizable("g1");
+ Group g1 = (Group) getUserManager().getAuthorizable("g1");
assertTrue(g1.isMember(user));
}
Modified: jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImportIgnoreTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImportIgnoreTest.java?rev=1756639&r1=1756638&r2=1756639&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImportIgnoreTest.java (original)
+++ jackrabbit/oak/branches/1.2/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImportIgnoreTest.java Wed Aug 17 14:21:07 2016
@@ -56,9 +56,9 @@ public class GroupImportIgnoreTest exten
"</sv:node>";
doImport(getTargetPath(), xml);
// no exception during import -> member must have been ignored though.
- Authorizable a = userMgr.getAuthorizable("g1");
+ Authorizable a = getUserManager().getAuthorizable("g1");
if (a.isGroup()) {
- assertNotDeclaredMember((Group) a, invalidId, adminSession);
+ assertNotDeclaredMember((Group) a, invalidId, getImportSession());
} else {
fail("'g1' was not imported as Group.");
}
@@ -84,14 +84,14 @@ public class GroupImportIgnoreTest exten
// there should be no exception during import,
// but invalid members must be ignored.
doImport(getTargetPath(), xml);
- Authorizable a = userMgr.getAuthorizable("g1");
+ Authorizable a = getUserManager().getAuthorizable("g1");
if (a.isGroup()) {
- assertNotDeclaredMember((Group) a, id, adminSession);
+ assertNotDeclaredMember((Group) a, id, getImportSession());
} else {
fail("'g1' was not imported as Group.");
}
} finally {
- adminSession.refresh(false);
+ getImportSession().refresh(false);
}
}
}