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 2012/05/31 14:17:03 UTC

svn commit: r1344670 [1/2] - in /jackrabbit/oak/trunk/oak-jcr/src/test: java/org/apache/jackrabbit/oak/jcr/ java/org/apache/jackrabbit/oak/jcr/security/ java/org/apache/jackrabbit/oak/jcr/security/user/ resources/

Author: angela
Date: Thu May 31 12:17:02 2012
New Revision: 1344670

URL: http://svn.apache.org/viewvc?rev=1344670&view=rev
Log:
OAK-50 : Implement User Management (WIP)

- tests + test setup that allows to extend from AbstractJcrTest

Added:
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OakRepositoryStub.java
      - copied, changed from r1342288, jackrabbit/oak/trunk/oak-it/jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OakRepositoryStub.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/TestContentLoader.java
      - copied, changed from r1342288, jackrabbit/oak/trunk/oak-it/jcr/src/test/java/org/apache/jackrabbit/oak/jcr/TestContentLoader.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AbstractUserTest.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AuthorizableImplTest.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/EveryoneGroupTest.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImplTest.java
    jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/ImpersonationImplTest.java
    jackrabbit/oak/trunk/oak-jcr/src/test/resources/repositoryStubImpl.properties
      - copied, changed from r1342288, jackrabbit/oak/trunk/oak-it/jcr/src/test/resources/repositoryStubImpl.properties

Copied: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OakRepositoryStub.java (from r1342288, jackrabbit/oak/trunk/oak-it/jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OakRepositoryStub.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OakRepositoryStub.java?p2=jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OakRepositoryStub.java&p1=jackrabbit/oak/trunk/oak-it/jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OakRepositoryStub.java&r1=1342288&r2=1344670&rev=1344670&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-it/jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OakRepositoryStub.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/OakRepositoryStub.java Thu May 31 12:17:02 2012
@@ -23,7 +23,6 @@ import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.jcr.UnsupportedRepositoryOperationException;
-
 import java.io.IOException;
 import java.security.Principal;
 import java.util.Properties;
@@ -37,7 +36,7 @@ public class OakRepositoryStub extends R
      * 
      * @param settings repository settings
      * @throws javax.jcr.RepositoryException If an error occurs.
-     * @throws IOException 
+     * @throws java.io.IOException
      */
     public OakRepositoryStub(Properties settings) throws RepositoryException, IOException {
         super(settings);

Copied: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/TestContentLoader.java (from r1342288, jackrabbit/oak/trunk/oak-it/jcr/src/test/java/org/apache/jackrabbit/oak/jcr/TestContentLoader.java)
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/TestContentLoader.java?p2=jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/TestContentLoader.java&p1=jackrabbit/oak/trunk/oak-it/jcr/src/test/java/org/apache/jackrabbit/oak/jcr/TestContentLoader.java&r1=1342288&r2=1344670&rev=1344670&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-it/jcr/src/test/java/org/apache/jackrabbit/oak/jcr/TestContentLoader.java (original)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/TestContentLoader.java Thu May 31 12:17:02 2012
@@ -16,19 +16,11 @@
  */
 package org.apache.jackrabbit.oak.jcr;
 
-import java.io.ByteArrayInputStream;
 import java.io.IOException;
-import java.util.Calendar;
-
 import javax.jcr.Node;
 import javax.jcr.PathNotFoundException;
-import javax.jcr.PropertyType;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
-import javax.jcr.ValueFactory;
-
-import org.apache.jackrabbit.commons.JcrUtils;
-import org.apache.jackrabbit.value.BinaryValue;
 
 public class TestContentLoader {
 
@@ -38,13 +30,7 @@ public class TestContentLoader {
     private static final String ENCODING = "UTF-8";
 
     public void loadTestContent(Session session) throws RepositoryException, IOException {
-
         Node data = getOrAddNode(session.getRootNode(), "testdata");
-        addPropertyTestData(getOrAddNode(data, "property"));
-        addQueryTestData(getOrAddNode(data, "query"));
-        addNodeTestData(getOrAddNode(data, "node"));
-        addExportTestData(getOrAddNode(data, "docViewTest"));
-
         session.save();
     }
 
@@ -55,127 +41,4 @@ public class TestContentLoader {
             return node.addNode(name);
         }
     }
-
-    /**
-     * Creates a boolean, double, long, calendar and a path property at the
-     * given node.
-     */
-    private void addPropertyTestData(Node node) throws RepositoryException {
-        node.setProperty("boolean", true);
-        node.setProperty("double", Math.PI);
-        node.setProperty("long", 90834953485278298l);
-        Calendar c = Calendar.getInstance();
-        c.set(2005, 6, 18, 17, 30);
-        node.setProperty("calendar", c);
-        ValueFactory factory = node.getSession().getValueFactory();
-        node.setProperty("path", factory.createValue("/", PropertyType.PATH));
-        node.setProperty("multi", new String[] { "one", "two", "three" });
-    }
-
-    /**
-     * Creates four nodes under the given node. Each node has a String property
-     * named "prop1" with some content set.
-     */
-    private void addQueryTestData(Node node) throws RepositoryException {
-        while (node.hasNode("node1")) {
-            node.getNode("node1").remove();
-        }
-        getOrAddNode(node, "node1").setProperty("prop1", "You can have it good, cheap, or fast. Any two.");
-        getOrAddNode(node, "node1").setProperty("prop1", "foo bar");
-        getOrAddNode(node, "node1").setProperty("prop1", "Hello world!");
-        getOrAddNode(node, "node2").setProperty("prop1", "Apache Jackrabbit");
-    }
-
-    /**
-     * Creates three nodes under the given node: one of type nt:resource and the
-     * other nodes referencing it.
-     */
-    private void addNodeTestData(Node node) throws RepositoryException, IOException {
-        if (node.hasNode("multiReference")) {
-            node.getNode("multiReference").remove();
-        }
-        if (node.hasNode("resReference")) {
-            node.getNode("resReference").remove();
-        }
-        if (node.hasNode("myResource")) {
-            node.getNode("myResource").remove();
-        }
-
-        Node resource = node.addNode("myResource", "nt:resource");
-        // nt:resource not longer referenceable since JCR 2.0
-        resource.addMixin("mix:referenceable");
-        resource.setProperty("jcr:encoding", ENCODING);
-        resource.setProperty("jcr:mimeType", "text/plain");
-        resource.setProperty("jcr:data", new BinaryValue("Hello w\u00F6rld.".getBytes(ENCODING)));
-        resource.setProperty("jcr:lastModified", Calendar.getInstance());
-
-        // TODO: re-add once we have referenceable nodes
-        // Node resReference = getOrAddNode(node, "reference");
-        // resReference.setProperty("ref", resource);
-        // // make this node itself referenceable
-        // resReference.addMixin("mix:referenceable");
-        //
-        // Node multiReference = node.addNode("multiReference");
-        // ValueFactory factory = node.getSession().getValueFactory();
-        // multiReference.setProperty("ref", new Value[] {
-        // factory.createValue(resource),
-        // factory.createValue(resReference)
-        // });
-
-        // NodeDefTest requires a test node with a mandatory child node
-        JcrUtils.putFile(node, "testFile", "text/plain", new ByteArrayInputStream("Hello, World!".getBytes("UTF-8")));
-    }
-
-    private void addExportTestData(Node node) throws RepositoryException, IOException {
-        getOrAddNode(node, "invalidXmlName").setProperty("propName", "some text");
-
-        // three nodes which should be serialized as xml text in docView export
-        // separated with spaces
-        getOrAddNode(node, "jcr:xmltext").setProperty("jcr:xmlcharacters", "A text without any special character.");
-        getOrAddNode(node, "some-element");
-        getOrAddNode(node, "jcr:xmltext").setProperty("jcr:xmlcharacters",
-                " The entity reference characters: <, ', ,&, >,  \" should" + " be escaped in xml export. ");
-        getOrAddNode(node, "some-element");
-        getOrAddNode(node, "jcr:xmltext").setProperty("jcr:xmlcharacters", "A text without any special character.");
-
-        Node big = getOrAddNode(node, "bigNode");
-        big.setProperty("propName0", "SGVsbG8gd8O2cmxkLg==;SGVsbG8gd8O2cmxkLg==".split(";"), PropertyType.BINARY);
-        big.setProperty("propName1", "text 1");
-        big.setProperty("propName2", "multival text 1;multival text 2;multival text 3".split(";"));
-        big.setProperty("propName3", "text 1");
-
-        addExportValues(node, "propName");
-        addExportValues(node, "Prop<>prop");
-    }
-
-    /**
-     * create nodes with following properties binary & single binary & multival
-     * notbinary & single notbinary & multival
-     */
-    private void addExportValues(Node node, String name) throws RepositoryException, IOException {
-        String prefix = "valid";
-        if (name.indexOf('<') != -1) {
-            prefix = "invalid";
-        }
-        node = getOrAddNode(node, prefix + "Names");
-
-        String[] texts = new String[] { "multival text 1", "multival text 2", "multival text 3" };
-        getOrAddNode(node, prefix + "MultiNoBin").setProperty(name, texts);
-
-        Node resource = getOrAddNode(node, prefix + "MultiBin");
-        resource.setProperty("jcr:encoding", ENCODING);
-        resource.setProperty("jcr:mimeType", "text/plain");
-        String[] values = new String[] { "SGVsbG8gd8O2cmxkLg==", "SGVsbG8gd8O2cmxkLg==" };
-        resource.setProperty(name, values, PropertyType.BINARY);
-        resource.setProperty("jcr:lastModified", Calendar.getInstance());
-
-        getOrAddNode(node, prefix + "NoBin").setProperty(name, "text 1");
-
-        resource = getOrAddNode(node, "invalidBin");
-        resource.setProperty("jcr:encoding", ENCODING);
-        resource.setProperty("jcr:mimeType", "text/plain");
-        byte[] bytes = "Hello w\u00F6rld.".getBytes(ENCODING);
-        resource.setProperty(name, new BinaryValue(bytes));
-        resource.setProperty("jcr:lastModified", Calendar.getInstance());
-    }
 }

Added: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AbstractUserTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AbstractUserTest.java?rev=1344670&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AbstractUserTest.java (added)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AbstractUserTest.java Thu May 31 12:17:02 2012
@@ -0,0 +1,115 @@
+/*
+ * 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.jcr.security.user;
+
+import java.security.Principal;
+import java.util.Collections;
+import java.util.UUID;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.security.auth.Subject;
+
+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.test.AbstractJCRTest;
+import org.apache.jackrabbit.test.NotExecutableException;
+import org.junit.After;
+import org.junit.Before;
+
+/**
+ * AbstractUserTest...
+ */
+public abstract class AbstractUserTest extends AbstractJCRTest {
+
+    protected UserManager userMgr;
+    protected User user;
+    protected Group group;
+
+    @Before
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        userMgr = getUserManager(superuser);
+
+        Principal p = getTestPrincipal();
+        user = userMgr.createUser(p.getName(), "pw");
+        group = userMgr.createGroup(getTestPrincipal());
+        superuser.save();
+    }
+
+    @After
+    @Override
+    protected void tearDown() throws Exception {
+        try {
+            if (user != null) {
+                user.remove();
+            }
+            if (group != null) {
+                group.remove();
+            }
+            superuser.save();
+        } finally {
+            super.tearDown();
+        }
+    }
+
+    protected static UserManager getUserManager(Session session) throws RepositoryException, NotExecutableException {
+        if (!(session instanceof JackrabbitSession)) {
+            throw new NotExecutableException();
+        }
+        try {
+            return ((JackrabbitSession) session).getUserManager();
+        } catch (UnsupportedRepositoryOperationException e) {
+            throw new NotExecutableException(e.getMessage());
+        } catch (UnsupportedOperationException e) {
+            throw new NotExecutableException(e.getMessage());
+        }
+    }
+
+    protected static Subject buildSubject(Principal p) {
+        return new Subject(true, Collections.singleton(p), Collections.emptySet(), Collections.emptySet());
+    }
+
+    protected Principal getTestPrincipal() throws RepositoryException {
+        String pn = "any_principal" + UUID.randomUUID();
+        return getTestPrincipal(pn);
+    }
+
+    protected Principal getTestPrincipal(final String name) throws RepositoryException {
+        return new Principal() {
+
+            @Override
+            public String getName() {
+                return name;
+            }
+        };
+    }
+
+    protected User getTestUser(Session session) throws NotExecutableException, RepositoryException {
+        Authorizable auth = getUserManager(session).getAuthorizable(session.getUserID());
+        if (auth != null && !auth.isGroup()) {
+            return (User) auth;
+        }
+        // should never happen. An Session should always have a corresponding User.
+        throw new NotExecutableException("Unable to retrieve a User.");
+    }
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AuthorizableImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AuthorizableImplTest.java?rev=1344670&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AuthorizableImplTest.java (added)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/AuthorizableImplTest.java Thu May 31 12:17:02 2012
@@ -0,0 +1,432 @@
+/*
+ * 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.jcr.security.user;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.test.NotExecutableException;
+import org.apache.jackrabbit.value.StringValue;
+import org.junit.Test;
+
+import javax.jcr.Node;
+import javax.jcr.Property;
+import javax.jcr.PropertyIterator;
+import javax.jcr.PropertyType;
+import javax.jcr.RangeIterator;
+import javax.jcr.RepositoryException;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.Value;
+import javax.jcr.nodetype.ConstraintViolationException;
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * AuthorizableImplTest...
+ */
+public class AuthorizableImplTest extends AbstractUserTest {
+
+    private List<String> protectedUserProps = new ArrayList<String>();
+    private List<String> protectedGroupProps = new ArrayList<String>();
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        protectedUserProps.add(UserConstants.REP_PASSWORD);
+        protectedUserProps.add(UserConstants.REP_IMPERSONATORS);
+        protectedUserProps.add(UserConstants.REP_PRINCIPAL_NAME);
+
+        protectedUserProps.add(UserConstants.REP_MEMBERS);
+        protectedGroupProps.add(UserConstants.REP_PRINCIPAL_NAME);
+    }
+
+    private static void checkProtected(Property prop) throws RepositoryException {
+        assertTrue(prop.getDefinition().isProtected());
+    }
+
+    @Test
+    public void testRemoveAdmin() {
+        String adminID = superuser.getUserID();
+        try {
+            Authorizable admin = userMgr.getAuthorizable(adminID);
+            admin.remove();
+            fail("The admin user cannot be removed.");
+        } catch (RepositoryException e) {
+            // OK superuser cannot be removed. not even by the superuser itself.
+        }
+    }
+
+    @Test
+    public void testSetSpecialProperties() throws NotExecutableException, RepositoryException {
+        Value v = superuser.getValueFactory().createValue("any_value");
+
+        for (String pName : protectedUserProps) {
+            try {
+                user.setProperty(pName, v);
+                superuser.save();
+                fail("changing the '" + pName + "' property on a User should fail.");
+            } catch (RepositoryException e) {
+                // success
+            }
+        }
+
+        for (String pName : protectedGroupProps) {
+            try {
+                group.setProperty(pName, v);
+                superuser.save();
+                fail("changing the '" + pName + "' property on a Group should fail.");
+            } catch (RepositoryException e) {
+                // success
+            }
+        }
+    }
+
+    @Test
+    public void testRemoveSpecialProperties() throws NotExecutableException, RepositoryException {
+        for (String pName : protectedUserProps) {
+            try {
+                user.removeProperty(pName);
+                superuser.save();
+                fail("removing the '" + pName + "' property on a User should fail.");
+            } catch (RepositoryException e) {
+                // success
+            }
+        }
+        for (String pName : protectedGroupProps) {
+            try {
+                group.removeProperty(pName);
+                superuser.save();
+                fail("removing the '" + pName + "' property on a Group should fail.");
+            } catch (RepositoryException e) {
+                // success
+            }
+        }
+    }
+
+    @Test
+    public void testProtectedUserProperties() throws NotExecutableException, RepositoryException {
+        UserImpl user = (UserImpl) getTestUser(superuser);
+        Node n = user.getNode();
+
+        checkProtected(n.getProperty(UserConstants.REP_PASSWORD));
+        if (n.hasProperty(UserConstants.REP_PRINCIPAL_NAME)) {
+            checkProtected(n.getProperty(UserConstants.REP_PRINCIPAL_NAME));
+        }
+        if (n.hasProperty(UserConstants.REP_IMPERSONATORS)) {
+           checkProtected(n.getProperty(UserConstants.REP_IMPERSONATORS));
+        }
+    }
+
+    @Test
+    public void testProtectedGroupProperties() throws NotExecutableException, RepositoryException {
+        Node n = ((GroupImpl) group).getNode();
+
+        if (n.hasProperty(UserConstants.REP_PRINCIPAL_NAME)) {
+            checkProtected(n.getProperty(UserConstants.REP_PRINCIPAL_NAME));
+        }
+        if (n.hasProperty(UserConstants.REP_MEMBERS)) {
+            checkProtected(n.getProperty(UserConstants.REP_MEMBERS));
+        }
+    }
+
+    @Test
+    public void testMembersPropertyType() throws NotExecutableException, RepositoryException {
+        Node n = ((GroupImpl) group).getNode();
+
+        if (!n.hasProperty(UserConstants.REP_MEMBERS)) {
+            group.addMember(getTestUser(superuser));
+        }
+
+        Property p = n.getProperty(UserConstants.REP_MEMBERS);
+        for (Value v : p.getValues()) {
+            assertEquals(PropertyType.WEAKREFERENCE, v.getType());
+        }
+    }
+
+    @Test
+    public void testMemberOfRangeIterator() throws NotExecutableException, RepositoryException {
+        Authorizable auth = null;
+        Group group = null;
+
+        try {
+            auth = userMgr.createUser(getTestPrincipal().getName(), "pw");
+            group = userMgr.createGroup(getTestPrincipal());
+            superuser.save();
+
+            Iterator<Group> groups = auth.declaredMemberOf();
+            assertTrue(groups instanceof RangeIterator);
+            assertEquals(0, ((RangeIterator) groups).getSize());
+            groups = auth.memberOf();
+            assertTrue(groups instanceof RangeIterator);
+            assertEquals(0, ((RangeIterator) groups).getSize());
+
+            group.addMember(auth);
+            groups = auth.declaredMemberOf();
+            assertTrue(groups instanceof RangeIterator);
+            assertEquals(1, ((RangeIterator) groups).getSize());
+
+            groups = auth.memberOf();
+            assertTrue(groups instanceof RangeIterator);
+            assertEquals(1, ((RangeIterator) groups).getSize());
+
+        } finally {
+            if (auth != null) {
+                auth.remove();
+            }
+            if (group != null) {
+                group.remove();
+            }
+            superuser.save();
+        }
+    }
+
+    @Test
+    public void testSetSpecialPropertiesDirectly() throws NotExecutableException, RepositoryException {
+        AuthorizableImpl user = (AuthorizableImpl) getTestUser(superuser);
+        Node n = user.getNode();
+        try {
+            String pName = user.getPrincipalName();
+            n.setProperty(UserConstants.REP_PRINCIPAL_NAME, new StringValue("any-value"));
+
+            // should have failed => change value back.
+            n.setProperty(UserConstants.REP_PRINCIPAL_NAME, new StringValue(pName));
+            fail("Attempt to change protected property rep:principalName should fail.");
+        } catch (ConstraintViolationException e) {
+            // ok.
+        }
+
+        try {
+            String imperson = "anyimpersonator";
+            n.setProperty(
+                    UserConstants.REP_IMPERSONATORS,
+                    new Value[] {new StringValue(imperson)},
+                    PropertyType.STRING);
+            fail("Attempt to change protected property rep:impersonators should fail.");
+        } catch (ConstraintViolationException e) {
+            // ok.
+        }
+    }
+
+    @Test
+    public void testRemoveSpecialUserPropertiesDirectly() throws RepositoryException, NotExecutableException {
+        AuthorizableImpl g = (AuthorizableImpl) getTestUser(superuser);
+        Node n = g.getNode();
+        try {
+            n.getProperty(UserConstants.REP_PASSWORD).remove();
+            fail("Attempt to remove protected property rep:password should fail.");
+        } catch (ConstraintViolationException e) {
+            // ok.
+        }
+        try {
+            if (n.hasProperty(UserConstants.REP_PRINCIPAL_NAME)) {
+                n.getProperty(UserConstants.REP_PRINCIPAL_NAME).remove();
+                fail("Attempt to remove protected property rep:principalName should fail.");
+            }
+        } catch (ConstraintViolationException e) {
+            // ok.
+        }
+    }
+
+    @Test
+    public void testRemoveSpecialGroupPropertiesDirectly() throws RepositoryException, NotExecutableException {
+        Node n = ((GroupImpl) group).getNode();
+        try {
+            if (n.hasProperty(UserConstants.REP_PRINCIPAL_NAME)) {
+                n.getProperty(UserConstants.REP_PRINCIPAL_NAME).remove();
+                fail("Attempt to remove protected property rep:principalName should fail.");
+            }
+        } catch (ConstraintViolationException e) {
+            // ok.
+        }
+        try {
+            if (n.hasProperty(UserConstants.REP_MEMBERS)) {
+                n.getProperty(UserConstants.REP_MEMBERS).remove();
+                fail("Attempt to remove protected property rep:members should fail.");
+            }
+        } catch (ConstraintViolationException e) {
+            // ok.
+        }
+    }
+
+    @Test
+    public void testUserGetProperties() throws RepositoryException, NotExecutableException {
+        AuthorizableImpl user = (AuthorizableImpl) getTestUser(superuser);
+        Node n = user.getNode();
+
+        for (PropertyIterator it = n.getProperties(); it.hasNext();) {
+            Property p = it.nextProperty();
+            if (p.getDefinition().isProtected()) {
+                assertFalse(user.hasProperty(p.getName()));
+                assertNull(user.getProperty(p.getName()));
+            } else {
+                // authorizable defined property
+                assertTrue(user.hasProperty(p.getName()));
+                assertNotNull(user.getProperty(p.getName()));
+            }
+        }
+    }
+
+    @Test
+    public void testGroupGetProperties() throws RepositoryException, NotExecutableException {
+        Node n = ((GroupImpl) group).getNode();
+
+        for (PropertyIterator it = n.getProperties(); it.hasNext();) {
+            Property prop = it.nextProperty();
+            if (prop.getDefinition().isProtected()) {
+                assertFalse(group.hasProperty(prop.getName()));
+                assertNull(group.getProperty(prop.getName()));
+            } else {
+                // authorizable defined property
+                assertTrue(group.hasProperty(prop.getName()));
+                assertNotNull(group.getProperty(prop.getName()));
+            }
+        }
+    }
+
+    @Test
+    public void testSingleToMultiValued() throws Exception {
+        AuthorizableImpl user = (AuthorizableImpl) getTestUser(superuser);
+        UserManager uMgr = getUserManager(superuser);
+        try {
+            Value v = superuser.getValueFactory().createValue("anyValue");
+            user.setProperty("someProp", v);
+            if (!uMgr.isAutoSave()) {
+                superuser.save();
+            }
+            Value[] vs = new Value[] {v, v};
+            user.setProperty("someProp", vs);
+            if (!uMgr.isAutoSave()) {
+                superuser.save();
+            }
+        } finally {
+            if (user.removeProperty("someProp") && !uMgr.isAutoSave()) {
+                superuser.save();
+            }
+        }
+    }
+
+    @Test
+    public void testMultiValuedToSingle() throws Exception {
+        AuthorizableImpl user = (AuthorizableImpl) getTestUser(superuser);
+        UserManager uMgr = getUserManager(superuser);
+        try {
+            Value v = superuser.getValueFactory().createValue("anyValue");
+            Value[] vs = new Value[] {v, v};
+            user.setProperty("someProp", vs);
+            if (!uMgr.isAutoSave()) {
+                superuser.save();
+            }
+            user.setProperty("someProp", v);
+            if (!uMgr.isAutoSave()) {
+                superuser.save();
+            }
+        } finally {
+            if (user.removeProperty("someProp") && !uMgr.isAutoSave()) {
+                superuser.save();
+            }
+        }
+    }
+
+    @Test
+    public void testObjectMethods() throws Exception {
+        final AuthorizableImpl user = (AuthorizableImpl) getTestUser(superuser);
+        AuthorizableImpl user2 = (AuthorizableImpl) getTestUser(superuser);
+
+        assertEquals(user, user2);
+        assertEquals(user.hashCode(), user2.hashCode());
+        Set<Authorizable> s = new HashSet<Authorizable>();
+        s.add(user);
+        assertFalse(s.add(user2));
+
+        Authorizable user3 = new Authorizable() {
+
+            public String getID() throws RepositoryException {
+                return user.getID();
+            }
+
+            public boolean isGroup() {
+                return user.isGroup();
+            }
+
+            public Principal getPrincipal() throws RepositoryException {
+                return user.getPrincipal();
+            }
+
+            public Iterator<Group> declaredMemberOf() throws RepositoryException {
+                return user.declaredMemberOf();
+            }
+
+            public Iterator<Group> memberOf() throws RepositoryException {
+                return user.memberOf();
+            }
+
+            public void remove() throws RepositoryException {
+                user.remove();
+            }
+
+            public Iterator<String> getPropertyNames() throws RepositoryException {
+                return user.getPropertyNames();
+            }
+
+            public Iterator<String> getPropertyNames(String relPath) throws RepositoryException {
+                return user.getPropertyNames(relPath);
+            }
+
+            public boolean hasProperty(String name) throws RepositoryException {
+                return user.hasProperty(name);
+            }
+
+            public void setProperty(String name, Value value) throws RepositoryException {
+                user.setProperty(name, value);
+            }
+
+            public void setProperty(String name, Value[] values) throws RepositoryException {
+                user.setProperty(name, values);
+            }
+
+            public Value[] getProperty(String name) throws RepositoryException {
+                return user.getProperty(name);
+            }
+
+            public boolean removeProperty(String name) throws RepositoryException {
+                return user.removeProperty(name);
+            }
+
+            public String getPath() throws UnsupportedRepositoryOperationException, RepositoryException {
+                return user.getPath();
+            }
+        };
+
+        assertFalse(user.equals(user3));
+        assertTrue(s.add(user3));
+    }
+
+    @Test
+    public void testGetPath() throws Exception {
+        AuthorizableImpl user = (AuthorizableImpl) getTestUser(superuser);
+        try {
+            assertEquals(user.getNode().getPath(), user.getPath());
+        } catch (UnsupportedRepositoryOperationException e) {
+            // ok.
+        }
+    }
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/EveryoneGroupTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/EveryoneGroupTest.java?rev=1344670&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/EveryoneGroupTest.java (added)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/EveryoneGroupTest.java Thu May 31 12:17:02 2012
@@ -0,0 +1,123 @@
+/*
+ * 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.jcr.security.user;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
+import org.apache.jackrabbit.test.NotExecutableException;
+import org.junit.Test;
+
+import javax.jcr.RepositoryException;
+import java.security.Principal;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * Tests for the group associated with {@code EveryonePrincipal}
+ */
+public class EveryoneGroupTest extends AbstractUserTest {
+
+    private Group everyone;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        everyone = userMgr.createGroup(EveryonePrincipal.NAME);
+        superuser.save();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        try {
+            everyone.remove();
+            superuser.save();
+        } finally {
+            super.tearDown();
+        }
+    }
+
+    @Test
+    public void testEveryoneGroup() throws RepositoryException, NotExecutableException {
+        assertEquals(EveryonePrincipal.NAME, everyone.getPrincipal().getName());
+    }
+
+    @Test
+    public void testPrincipal() throws RepositoryException {
+        assertEquals(EveryonePrincipal.getInstance(), everyone.getPrincipal());
+    }
+
+    @Test
+    public void testGroupPrincipal() throws Exception {
+        Principal everonePrincipal = everyone.getPrincipal();
+        assertTrue(everonePrincipal instanceof java.security.acl.Group);
+
+        java.security.acl.Group gr = (java.security.acl.Group) everonePrincipal;
+        assertFalse(gr.isMember(everonePrincipal));
+        assertTrue(gr.isMember(getTestUser(superuser).getPrincipal()));
+        assertTrue(gr.isMember(new Principal() {
+            public String getName() {
+                return "test";
+            }
+        }));
+    }
+
+    @Test
+    public void testMembers() throws RepositoryException, NotExecutableException {
+        assertTrue(everyone.isDeclaredMember(getTestUser(superuser)));
+        assertTrue(everyone.isMember(getTestUser(superuser)));
+
+        Iterator<Authorizable> it = everyone.getDeclaredMembers();
+        assertTrue(it.hasNext());
+        Set<Authorizable> members = new HashSet<Authorizable>();
+        while (it.hasNext()) {
+            members.add(it.next());
+        }
+
+        it = everyone.getMembers();
+        assertTrue(it.hasNext());
+        while (it.hasNext()) {
+            assertTrue(members.contains(it.next()));
+        }
+    }
+
+    @Test
+    public void testEditMembers() throws RepositoryException, NotExecutableException {
+        assertFalse(everyone.addMember(getTestUser(superuser)));
+        assertFalse(everyone.removeMember(getTestUser(superuser)));
+
+        Group anotherGroup =  null;
+        try {
+            anotherGroup = userMgr.createGroup("testGroup");
+            superuser.save();
+
+            assertFalse(everyone.addMember(anotherGroup));
+            assertFalse(everyone.removeMember(anotherGroup));
+
+            assertFalse(anotherGroup.addMember(everyone));
+            assertFalse(anotherGroup.removeMember(everyone));
+
+        } finally {
+            if (anotherGroup != null) {
+                anotherGroup.remove();
+                superuser.save();
+            }
+        }
+    }
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImplTest.java?rev=1344670&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImplTest.java (added)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/GroupImplTest.java Thu May 31 12:17:02 2012
@@ -0,0 +1,672 @@
+/*
+ * 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.jcr.security.user;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import javax.jcr.RepositoryException;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.AuthorizableExistsException;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.test.NotExecutableException;
+import org.junit.Before;
+import org.junit.Test;
+
+/**
+ * GroupImplTest...
+ */
+public class GroupImplTest extends AbstractUserTest {
+
+    private List<String> members = new ArrayList<String>();
+
+    @Before
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        group.addMember(userMgr.getAuthorizable(superuser.getUserID()));
+        group.addMember(user);
+
+        members.add(superuser.getUserID());
+        members.add(user.getID());
+
+        superuser.save();
+    }
+
+    private static void assertTrueIsMember(Iterator<Authorizable> members, Authorizable auth) throws RepositoryException {
+        boolean contained = false;
+        while (members.hasNext() && !contained) {
+            Object next = members.next();
+            assertTrue(next instanceof Authorizable);
+            contained = ((Authorizable)next).getID().equals(auth.getID());
+        }
+        assertTrue("The given set of members must contain '" + auth.getID() + '\'', contained);
+    }
+
+    private static void assertFalseIsMember(Iterator<Authorizable> members, Authorizable auth) throws RepositoryException {
+        boolean contained = false;
+        while (members.hasNext() && !contained) {
+            Object next = members.next();
+            assertTrue(next instanceof Authorizable);
+            contained = ((Authorizable)next).getID().equals(auth.getID());
+        }
+        assertFalse("The given set of members must not contain '" + auth.getID() + '\'', contained);
+    }
+
+    private static void assertTrueMemberOfContainsGroup(Iterator<Group> groups, Group gr) throws RepositoryException {
+        boolean contained = false;
+        while (groups.hasNext() && !contained) {
+            Object next = groups.next();
+            assertTrue(next instanceof Group);
+            contained = ((Group)next).getID().equals(gr.getID());
+        }
+        assertTrue("All members of a group must contain that group upon 'memberOf'.", contained);
+    }
+
+    private static void assertFalseMemberOfContainsGroup(Iterator<Group> groups, Group gr) throws RepositoryException {
+        boolean contained = false;
+        while (groups.hasNext() && !contained) {
+            Object next = groups.next();
+            assertTrue(next instanceof Group);
+            contained = ((Group)next).getID().equals(gr.getID());
+        }
+        assertFalse("All members of a group must contain that group upon 'memberOf'.", contained);
+    }
+
+    @Test
+    public void testIsGroup() throws NotExecutableException, RepositoryException {
+        assertTrue(group.isGroup());
+    }
+
+    @Test
+    public void testGetDeclaredMembers() throws NotExecutableException, RepositoryException {
+        Iterator<Authorizable> it = group.getDeclaredMembers();
+        assertNotNull(it);
+        while (it.hasNext()) {
+            Authorizable a = it.next();
+            assertNotNull(a);
+            members.remove(a.getID());
+        }
+        assertTrue(members.isEmpty());
+    }
+
+    @Test
+    public void testGetMembers() throws NotExecutableException, RepositoryException {
+        Iterator<Authorizable> it = group.getMembers();
+        assertNotNull(it);
+        while (it.hasNext()) {
+            assertTrue(it.next() != null);
+        }
+    }
+
+    @Test
+    public void testGetMembersAgainstIsMember() throws NotExecutableException, RepositoryException {
+        Iterator<Authorizable> it = group.getMembers();
+        while (it.hasNext()) {
+            Authorizable auth = it.next();
+            assertTrue(group.isMember(auth));
+        }
+    }
+
+    @Test
+    public void testGetMembersAgainstMemberOf() throws NotExecutableException, RepositoryException {
+        Iterator<Authorizable> it = group.getMembers();
+        while (it.hasNext()) {
+            Authorizable auth = it.next();
+            assertTrueMemberOfContainsGroup(auth.memberOf(), group);
+        }
+    }
+
+    @Test
+    public void testGetDeclaredMembersAgainstDeclaredMemberOf() throws NotExecutableException, RepositoryException {
+        Iterator<Authorizable> it = group.getDeclaredMembers();
+        while (it.hasNext()) {
+            Authorizable auth = it.next();
+            assertTrueMemberOfContainsGroup(auth.declaredMemberOf(), group);
+        }
+    }
+
+    @Test
+    public void testGetMembersContainsDeclaredMembers() throws NotExecutableException, RepositoryException {
+        List<String> l = new ArrayList<String>();
+        for (Iterator<Authorizable> it = group.getMembers(); it.hasNext();) {
+            l.add(it.next().getID());
+        }
+        for (Iterator<Authorizable> it = group.getDeclaredMembers(); it.hasNext();) {
+            assertTrue("All declared members must also be part of the Iterator " +
+                    "returned upon getMembers()",l.contains(it.next().getID()));
+        }
+    }
+
+    @Test
+    public void testAddMember() throws NotExecutableException, RepositoryException {
+        User auth = getTestUser(superuser);
+        Group newGroup = null;
+        try {
+            newGroup = userMgr.createGroup(getTestPrincipal());
+            superuser.save();
+
+            assertFalse(newGroup.isMember(auth));
+            assertFalse(newGroup.removeMember(auth));
+            superuser.save();
+
+            assertTrue(newGroup.addMember(auth));
+            superuser.save();
+            assertTrue(newGroup.isMember(auth));
+            assertTrue(newGroup.isMember(userMgr.getAuthorizable(auth.getID())));
+
+        } finally {
+            if (newGroup != null) {
+                newGroup.removeMember(auth);
+                newGroup.remove();
+                superuser.save();
+            }
+        }
+    }
+
+    @Test
+    public void testAddMembers() throws NotExecutableException, RepositoryException {
+        User auth = getTestUser(superuser);
+        Group newGroup = null;
+        int size = 100;
+        List<User> users = new ArrayList<User>(size);
+        try {
+            newGroup = userMgr.createGroup(getTestPrincipal());
+            superuser.save();
+
+            for (int k = 0; k < size; k++) {
+                users.add(userMgr.createUser("user_" + k, "pass_" + k));
+            }
+            superuser.save();
+
+            for (User user : users) {
+                assertTrue(newGroup.addMember(user));
+            }
+            superuser.save();
+
+            for (User user : users) {
+                assertTrue(newGroup.isMember(user));
+            }
+
+            for (User user : users) {
+                assertTrue(newGroup.removeMember(user));
+            }
+            superuser.save();
+
+            for (User user : users) {
+                assertFalse(newGroup.isMember(user));
+            }
+        } finally {
+            for (User user : users) {
+                user.remove();
+                superuser.save();
+            }
+            if (newGroup != null) {
+                newGroup.removeMember(auth);
+                newGroup.remove();
+                superuser.save();
+            }
+        }
+    }
+
+    @Test
+    public void testAddRemoveMember() throws NotExecutableException, RepositoryException {
+        User auth = getTestUser(superuser);
+        Group newGroup1 = null;
+        Group newGroup2 = null;
+        try {
+            newGroup1 = userMgr.createGroup(getTestPrincipal());
+            newGroup2 = userMgr.createGroup(getTestPrincipal());
+            superuser.save();
+
+            assertFalse(newGroup1.isMember(auth));
+            assertFalse(newGroup1.removeMember(auth));
+            superuser.save();
+            assertFalse(newGroup2.isMember(auth));
+            assertFalse(newGroup2.removeMember(auth));
+            superuser.save();
+
+            assertTrue(newGroup1.addMember(auth));
+            superuser.save();
+            assertTrue(newGroup1.isMember(auth));
+            assertTrue(newGroup1.isMember(userMgr.getAuthorizable(auth.getID())));
+
+            assertTrue(newGroup2.addMember(auth));
+            superuser.save();
+            assertTrue(newGroup2.isMember(auth));
+            assertTrue(newGroup2.isMember(userMgr.getAuthorizable(auth.getID())));
+
+            assertTrue(newGroup1.removeMember(auth));
+            superuser.save();
+            assertTrue(newGroup2.removeMember(auth));
+            superuser.save();
+
+            assertTrue(newGroup1.addMember(auth));
+            superuser.save();
+            assertTrue(newGroup1.isMember(auth));
+            assertTrue(newGroup1.isMember(userMgr.getAuthorizable(auth.getID())));
+            assertTrue(newGroup1.removeMember(auth));
+            superuser.save();
+
+
+        } finally {
+            if (newGroup1 != null) {
+                newGroup1.removeMember(auth);
+                newGroup1.remove();
+                superuser.save();
+            }
+            if (newGroup2 != null) {
+                newGroup2.removeMember(auth);
+                newGroup2.remove();
+                superuser.save();
+            }
+        }
+    }
+
+    @Test
+    public void testIsDeclaredMember() throws RepositoryException, NotExecutableException {
+        User auth = getTestUser(superuser);
+        Group newGroup1 = null;
+        Group newGroup2 = null;
+        try {
+            newGroup1 = userMgr.createGroup(getTestPrincipal());
+            newGroup2 = userMgr.createGroup(getTestPrincipal());
+            superuser.save();
+
+            assertFalse(newGroup1.isDeclaredMember(auth));
+            assertFalse(newGroup2.isDeclaredMember(auth));
+
+            assertTrue(newGroup2.addMember(auth));
+            superuser.save();
+            assertTrue(newGroup2.isDeclaredMember(auth));
+            assertTrue(newGroup2.isDeclaredMember(userMgr.getAuthorizable(auth.getID())));
+
+            assertTrue(newGroup1.addMember(newGroup2));
+            superuser.save();
+            assertTrue(newGroup1.isDeclaredMember(newGroup2));
+            assertTrue(newGroup1.isDeclaredMember(userMgr.getAuthorizable(newGroup2.getID())));
+            assertTrue(newGroup1.isMember(auth));
+            assertTrue(newGroup1.isMember(userMgr.getAuthorizable(auth.getID())));
+            assertFalse(newGroup1.isDeclaredMember(auth));
+            assertFalse(newGroup1.isDeclaredMember(userMgr.getAuthorizable(auth.getID())));
+        } finally {
+            if (newGroup1 != null) {
+                newGroup1.remove();
+                superuser.save();
+            }
+            if (newGroup2 != null) {
+                newGroup2.remove();
+                superuser.save();
+            }
+        }
+    }
+
+    @Test
+    public void testAddMemberTwice() throws NotExecutableException, RepositoryException {
+        User auth = getTestUser(superuser);
+        Group newGroup = null;
+        try {
+            newGroup = userMgr.createGroup(getTestPrincipal());
+            superuser.save();
+
+            assertTrue(newGroup.addMember(auth));
+            superuser.save();
+            assertFalse(newGroup.addMember(auth));
+            superuser.save();
+            assertTrue(newGroup.isMember(auth));
+
+        } finally {
+            if (newGroup != null) {
+                newGroup.removeMember(auth);
+                newGroup.remove();
+                superuser.save();
+            }
+        }
+    }
+
+    @Test
+    public void testAddMemberModifiesMemberOf() throws NotExecutableException, RepositoryException {
+        User auth = getTestUser(superuser);
+        Group newGroup = null;
+        try {
+            newGroup = userMgr.createGroup(getTestPrincipal());
+            superuser.save();
+
+            assertFalseMemberOfContainsGroup(auth.memberOf(), newGroup);
+            assertTrue(newGroup.addMember(auth));
+            superuser.save();
+
+            assertTrueMemberOfContainsGroup(auth.declaredMemberOf(), newGroup);
+            assertTrueMemberOfContainsGroup(auth.memberOf(), newGroup);
+        } finally {
+            if (newGroup != null) {
+                newGroup.removeMember(auth);
+                newGroup.remove();
+                superuser.save();
+            }
+        }
+    }
+
+    @Test
+    public void testAddMemberModifiesGetMembers() throws NotExecutableException, RepositoryException {
+        User auth = getTestUser(superuser);
+        Group newGroup = null;
+        try {
+            newGroup = userMgr.createGroup(getTestPrincipal());
+            superuser.save();
+
+            assertFalseIsMember(newGroup.getMembers(), auth);
+            assertFalseIsMember(newGroup.getDeclaredMembers(), auth);
+            assertTrue(newGroup.addMember(auth));
+            superuser.save();
+
+            assertTrueIsMember(newGroup.getMembers(), auth);
+            assertTrueIsMember(newGroup.getDeclaredMembers(), auth);
+        } finally {
+            if (newGroup != null) {
+                newGroup.removeMember(auth);
+                newGroup.remove();
+                superuser.save();
+            }
+        }
+    }
+
+    @Test
+    public void testIndirectMembers() throws NotExecutableException, RepositoryException {
+        User auth = getTestUser(superuser);
+        Group newGroup = null;
+        Group newGroup2 = null;
+        try {
+            newGroup = userMgr.createGroup(getTestPrincipal());
+            newGroup2 = userMgr.createGroup(getTestPrincipal());
+            superuser.save();
+
+            newGroup.addMember(newGroup2);
+            superuser.save();
+            assertTrue(newGroup.isMember(newGroup2));
+
+            newGroup2.addMember(auth);
+            superuser.save();
+
+            // testuser must not be declared member of 'newGroup'
+            assertFalseIsMember(newGroup.getDeclaredMembers(), auth);
+            assertFalseMemberOfContainsGroup(auth.declaredMemberOf(), newGroup);
+
+            // testuser must however be member of 'newGroup' (indirect).
+            assertTrueIsMember(newGroup.getMembers(), auth);
+            assertTrueMemberOfContainsGroup(auth.memberOf(), newGroup);
+
+            // testuser cannot be removed from 'newGroup'
+            assertFalse(newGroup.removeMember(auth));
+            superuser.save();
+        } finally {
+            if (newGroup != null) {
+                newGroup.removeMember(newGroup2);
+                newGroup.remove();
+                superuser.save();
+            }
+            if (newGroup2 != null) {
+                newGroup2.removeMember(auth);
+                newGroup2.remove();
+                superuser.save();
+            }
+        }
+    }
+
+    @Test
+    public void testMembersInPrincipal() throws NotExecutableException, RepositoryException {
+        User auth = getTestUser(superuser);
+        Group newGroup = null;
+        Group newGroup2 = null;
+        try {
+            newGroup = userMgr.createGroup(getTestPrincipal());
+            newGroup2 = userMgr.createGroup(getTestPrincipal());
+            superuser.save();
+
+            newGroup.addMember(newGroup2);
+            superuser.save();
+            newGroup2.addMember(auth);
+            superuser.save();
+
+            java.security.acl.Group ngPrincipal = (java.security.acl.Group) newGroup.getPrincipal();
+            java.security.acl.Group ng2Principal = (java.security.acl.Group) newGroup2.getPrincipal();
+
+            assertFalse(ng2Principal.isMember(ngPrincipal));
+
+            // newGroup2 must be member of newGroup's principal
+            assertTrue(ngPrincipal.isMember(newGroup2.getPrincipal()));
+
+            // testuser must be member of newGroup2's and newGroup's principal (indirect)
+            assertTrue(ng2Principal.isMember(auth.getPrincipal()));
+            assertTrue(ngPrincipal.isMember(auth.getPrincipal()));
+
+        } finally {
+            if (newGroup != null) {
+                newGroup.removeMember(newGroup2);
+                newGroup.remove();
+                superuser.save();
+            }
+            if (newGroup2 != null) {
+                newGroup2.removeMember(auth);
+                newGroup2.remove();
+                superuser.save();
+            }
+        }
+    }
+
+    @Test
+    public void testDeeplyNestedGroups() throws NotExecutableException, RepositoryException {
+        Set<Group> groups = new HashSet<Group>();
+        try {
+            User auth = getTestUser(superuser);
+            Group topGroup = userMgr.createGroup(getTestPrincipal());
+
+            // Create chain of nested groups with auth member of bottom group
+            Group bottomGroup = topGroup;
+            for (int k = 0; k < 100; k++) {
+                Group g = userMgr.createGroup(getTestPrincipal());
+                groups.add(g);
+                bottomGroup.addMember(g);
+                bottomGroup = g;
+            }
+            bottomGroup.addMember(auth);
+
+            // Check that every groups has exactly one member
+            for (Group g : groups) {
+                Iterator<Authorizable> declaredMembers = g.getDeclaredMembers();
+                assertTrue(declaredMembers.hasNext());
+                declaredMembers.next();
+                assertFalse(declaredMembers.hasNext());
+            }
+
+            // Check that we get all members from the getMembers call
+            HashSet<Group> allGroups = new HashSet<Group>(groups);
+            for (Iterator<Authorizable> it = topGroup.getMembers(); it.hasNext(); ) {
+                Authorizable a = it.next();
+                assertTrue(a.equals(auth) || allGroups.remove(a));
+            }
+            assertTrue(allGroups.isEmpty());
+        } finally {
+            for (Group g : groups) {
+                g.remove();
+            }
+        }
+    }
+
+    @Test
+    public void testInheritedMembers() throws Exception {
+        Set<Authorizable> authorizables = new HashSet<Authorizable>();
+        try {
+            User testUser = userMgr.createUser(getTestPrincipal().getName(), "pw");
+            authorizables.add(testUser);
+            Group group1 = userMgr.createGroup(getTestPrincipal());
+            authorizables.add(group1);
+            Group group2 = userMgr.createGroup(getTestPrincipal());
+            authorizables.add(group2);
+            Group group3 = userMgr.createGroup(getTestPrincipal());
+
+            group1.addMember(testUser);
+            group2.addMember(testUser);
+            group3.addMember(group1);
+            group3.addMember(group2);
+
+            Iterator<Authorizable> members = group3.getMembers();
+            while (members.hasNext()) {
+                Authorizable a = members.next();
+                assertTrue(authorizables.contains(a));
+                assertTrue(authorizables.remove(a));
+            }
+
+            assertTrue(authorizables.isEmpty());
+        } finally {
+            for (Authorizable a : authorizables) {
+                a.remove();
+            }
+        }
+    }
+
+    @Test
+    public void testCyclicGroups() throws AuthorizableExistsException, RepositoryException, NotExecutableException {
+        Group group1 = null;
+        Group group2 = null;
+        Group group3 = null;
+        try {
+            group1 = userMgr.createGroup(getTestPrincipal());
+            group2 = userMgr.createGroup(getTestPrincipal());
+            group3 = userMgr.createGroup(getTestPrincipal());
+
+            group1.addMember(getTestUser(superuser));
+            group2.addMember(getTestUser(superuser));
+
+            assertTrue(group1.addMember(group2));
+            assertTrue(group2.addMember(group3));
+            assertFalse(group3.addMember(group1));
+        }
+        finally {
+            if (group1 != null) group1.remove();
+            if (group2 != null) group2.remove();
+            if (group3 != null) group3.remove();
+        }
+    }
+
+    @Test
+    public void testRemoveMemberTwice() throws NotExecutableException, RepositoryException {
+        User auth = getTestUser(superuser);
+        Group newGroup = null;
+        try {
+            newGroup = userMgr.createGroup(getTestPrincipal());
+            superuser.save();
+
+            assertTrue(newGroup.addMember(auth));
+            superuser.save();
+            assertTrue(newGroup.removeMember(userMgr.getAuthorizable(auth.getID())));
+            superuser.save();
+            assertFalse(newGroup.removeMember(auth));
+            superuser.save();
+        } finally {
+            if (newGroup != null) {
+                newGroup.remove();
+                superuser.save();
+            }
+        }
+    }
+
+    @Test
+    public void testAddItselfAsMember() throws RepositoryException, NotExecutableException {
+        Group newGroup = null;
+        try {
+            newGroup = userMgr.createGroup(getTestPrincipal());
+            superuser.save();
+
+            assertFalse(newGroup.addMember(newGroup));
+            superuser.save();
+            newGroup.removeMember(newGroup);
+            superuser.save();
+        } finally {
+            if (newGroup != null) {
+                newGroup.remove();
+                superuser.save();
+            }
+        }
+    }
+
+    @Test
+    public void testRemoveGroupIfMemberExist() throws RepositoryException, NotExecutableException {
+        User auth = getTestUser(superuser);
+        String newGroupId = null;
+
+        try {
+            Group newGroup = userMgr.createGroup(getTestPrincipal());
+            superuser.save();
+            newGroupId = newGroup.getID();
+
+            assertTrue(newGroup.addMember(auth));
+            newGroup.remove();
+            superuser.save();
+        } finally {
+            Group gr = (Group) userMgr.getAuthorizable(newGroupId);
+            if (gr != null) {
+                gr.removeMember(auth);
+                gr.remove();
+                superuser.save();
+            }
+        }
+    }
+
+    @Test
+    public void testRemoveGroupClearsMembership() throws NotExecutableException, RepositoryException {
+        User auth = getTestUser(superuser);
+        Group newGroup = null;
+        String groupId;
+        try {
+            newGroup = userMgr.createGroup(getTestPrincipal());
+            groupId = newGroup.getID();
+            superuser.save();
+
+            assertTrue(newGroup.addMember(auth));
+            superuser.save();
+
+            boolean isMember = false;
+            Iterator<Group> it = auth.declaredMemberOf();
+            while (it.hasNext() && !isMember) {
+                isMember = groupId.equals(it.next().getID());
+            }
+            assertTrue(isMember);
+
+        } finally {
+            if (newGroup != null) {
+                newGroup.remove();
+                superuser.save();
+            }
+        }
+
+        Iterator<Group> it = auth.declaredMemberOf();
+        while (it.hasNext()) {
+            assertFalse(groupId.equals(it.next().getID()));
+        }
+
+        it = auth.memberOf();
+        while (it.hasNext()) {
+            assertFalse(groupId.equals(it.next().getID()));
+        }
+    }
+}
\ No newline at end of file

Added: jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/ImpersonationImplTest.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/ImpersonationImplTest.java?rev=1344670&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/ImpersonationImplTest.java (added)
+++ jackrabbit/oak/trunk/oak-jcr/src/test/java/org/apache/jackrabbit/oak/jcr/security/user/ImpersonationImplTest.java Thu May 31 12:17:02 2012
@@ -0,0 +1,101 @@
+/*
+ * 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.jcr.security.user;
+
+import java.security.Principal;
+import java.util.Collections;
+import javax.jcr.RepositoryException;
+import javax.security.auth.Subject;
+
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Impersonation;
+import org.apache.jackrabbit.api.security.user.User;
+import org.apache.jackrabbit.test.NotExecutableException;
+import org.junit.Test;
+
+/**
+ * ImpersonationImplTest...
+ */
+public class ImpersonationImplTest extends AbstractUserTest {
+
+    private User user2;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        user2 = userMgr.createUser("user2", "pw");
+        superuser.save();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        try {
+            user2.remove();
+            superuser.save();
+        } finally {
+            super.tearDown();
+        }
+    }
+
+    @Test
+    public void testImpersonation() throws RepositoryException, NotExecutableException {
+        Principal user2Principal = user2.getPrincipal();
+        Subject subject = new Subject(true, Collections.singleton(user2Principal), Collections.<Object>emptySet(), Collections.<Object>emptySet());
+
+        Impersonation impers = user.getImpersonation();
+        assertFalse(impers.allows(subject));
+
+        assertTrue(impers.grantImpersonation(user2Principal));
+        assertFalse(impers.grantImpersonation(user2Principal));
+        superuser.save();
+
+        assertTrue(impers.allows(subject));
+
+        assertTrue(impers.revokeImpersonation(user2Principal));
+        assertFalse(impers.revokeImpersonation(user2Principal));
+        superuser.save();
+
+        assertFalse(impers.allows(subject));
+    }
+
+    @Test
+    public void testAdminPrincipalAsImpersonator() throws RepositoryException, NotExecutableException {
+        String adminId = superuser.getUserID();
+        Authorizable admin = userMgr.getAuthorizable(adminId);
+        if (admin == null || admin.isGroup() || !((User) admin).isAdmin()) {
+            throw new NotExecutableException(adminId + " is not administators ID");
+        }
+
+        Principal adminPrincipal = admin.getPrincipal();
+
+        // admin cannot be add/remove to set of impersonators of 'u' but is
+        // always allowed to impersonate that user.
+        Impersonation impersonation = user.getImpersonation();
+
+        assertFalse(impersonation.grantImpersonation(adminPrincipal));
+        assertFalse(impersonation.revokeImpersonation(adminPrincipal));
+        assertTrue(impersonation.allows(buildSubject(adminPrincipal)));
+
+        // same if the impersonation object of the admin itself is used.
+        Impersonation adminImpersonation = ((User) admin).getImpersonation();
+
+        assertFalse(adminImpersonation.grantImpersonation(adminPrincipal));
+        assertFalse(adminImpersonation.revokeImpersonation(adminPrincipal));
+        assertTrue(impersonation.allows(buildSubject(adminPrincipal)));
+    }
+}
\ No newline at end of file