Modified: 
jackrabbit/oak/branches/1.2/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/PathUtils.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/PathUtils.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/PathUtils.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/PathUtils.java
 Thu Aug 18 13:15:22 2016
@@ -22,6 +22,7 @@ import java.util.Set;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 
 import static com.google.common.collect.Sets.newHashSet;
@@ -320,6 +321,36 @@ public final class PathUtils {
     }
 
     /**
+     * Relative path concatenation.
+     *
+     * @param relativePaths relative paths
+     * @return the concatenated path or {@code null} if the resulting path is 
empty.
+     */
+    @CheckForNull
+    public static String concatRelativePaths(String... relativePaths) {
+        StringBuilder result = new StringBuilder();
+        for (String path : relativePaths) {
+            if (path != null && !path.isEmpty()) {
+                int i0 = 0;
+                int i1 = path.length();
+                while (i0 < i1 && path.charAt(i0) == '/') {
+                    i0++;
+                }
+                while (i1 > i0 && path.charAt(i1-1) == '/') {
+                    i1--;
+                }
+                if (i1 > i0) {
+                    if (result.length() > 0) {
+                        result.append('/');
+                    }
+                    result.append(path.substring(i0, i1));
+                }
+            }
+        }
+        return result.length() == 0 ? null : result.toString();
+    }
+
+    /**
      * Check if a path is a (direct or indirect) ancestor of another path.
      *
      * @param ancestor the ancestor path

Modified: 
jackrabbit/oak/branches/1.2/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-commons/src/main/java/org/apache/jackrabbit/oak/commons/package-info.java
 Thu Aug 18 13:15:22 2016
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.1")
+@Version("1.2.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.commons;
 

Modified: 
jackrabbit/oak/branches/1.2/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/PathUtilsTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/PathUtilsTest.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/PathUtilsTest.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-commons/src/test/java/org/apache/jackrabbit/oak/commons/PathUtilsTest.java
 Thu Aug 18 13:15:22 2016
@@ -75,6 +75,18 @@ public class PathUtilsTest extends TestC
         assertEquals(2, PathUtils.getDepth("a/b"));
     }
 
+    @Test
+    public void testConcatRelativePaths() {
+        assertNull(PathUtils.concatRelativePaths("", "", ""));
+        assertNull(PathUtils.concatRelativePaths());
+
+        assertEquals("a/b/c", PathUtils.concatRelativePaths("a", "b", "c"));
+        assertEquals("a/b/c", PathUtils.concatRelativePaths("a", "b/c"));
+        assertEquals("a/b/c", PathUtils.concatRelativePaths("a/b/c", ""));
+        assertEquals("a/b/c", PathUtils.concatRelativePaths("a/b", "c"));
+        assertEquals("a/b/c", PathUtils.concatRelativePaths("/", "a", "", 
"b/c/"));
+    }
+
 
     private static int getElementCount(String path) {
         int count = 0;

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypePredicate.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypePredicate.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypePredicate.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/TypePredicate.java
 Thu Aug 18 13:15:22 2016
@@ -25,8 +25,10 @@ import javax.annotation.Nullable;
 import com.google.common.base.Predicate;
 import com.google.common.collect.Iterables;
 
+import org.apache.jackrabbit.oak.api.Tree;
 import org.apache.jackrabbit.oak.spi.state.ChildNodeEntry;
 import org.apache.jackrabbit.oak.spi.state.NodeState;
+import org.apache.jackrabbit.oak.util.TreeUtil;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.base.Predicates.in;
@@ -165,6 +167,21 @@ public class TypePredicate implements Pr
         }
         return false;
     }
+
+    public boolean apply(@Nullable Tree input) {
+        if (input != null) {
+            init();
+            if (primaryTypes != null
+                    && 
primaryTypes.contains(TreeUtil.getPrimaryTypeName(input))) {
+                return true;
+            }
+            if (mixinTypes != null
+                    && any(TreeUtil.getNames(input, JCR_MIXINTYPES), 
in(mixinTypes))) {
+                return true;
+            }
+        }
+        return false;
+    }
 
     //---------------------------------------------------------< Predicate >--
 

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/package-info.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/package-info.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/package-info.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/plugins/nodetype/package-info.java
 Thu Aug 18 13:15:22 2016
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.0")
+@Version("1.1.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.plugins.nodetype;
 

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImpl.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImpl.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/authorization/permission/PermissionEntryProviderImpl.java
 Thu Aug 18 13:15:22 2016
@@ -30,6 +30,7 @@ import com.google.common.base.Strings;
 import com.google.common.collect.Iterators;
 import org.apache.jackrabbit.commons.iterator.AbstractLazyIterator;
 import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.LongUtils;
 import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
 import 
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
 
@@ -95,7 +96,7 @@ class PermissionEntryProviderImpl implem
                 if (Long.MAX_VALUE == n) {
                     cnt = Long.MAX_VALUE;
                 } else {
-                    cnt = safeAdd(cnt, n);
+                    cnt = LongUtils.safeAdd(cnt, n);
                 }
             }
         }
@@ -161,25 +162,6 @@ class PermissionEntryProviderImpl implem
         return ret;
     }
 
-    /**
-     * Sums {@code a} and {@code b} and verifies that it doesn't overflow in
-     * signed long arithmetic, in which case {@link Long#MAX_VALUE} will be
-     * returned instead of the result.
-     *
-     * Note: this method is a variant of {@link 
com.google.common.math.LongMath#checkedAdd(long, long)}
-     * that returns {@link Long#MAX_VALUE} instead of throwing {@code 
ArithmeticException}.
-     *
-     * @see com.google.common.math.LongMath#checkedAdd(long, long)
-     */
-    private static long safeAdd(long a, long b) {
-        long result = a + b;
-        if ((a ^ b) < 0 | (a ^ result) >= 0) {
-            return result;
-        } else {
-            return Long.MAX_VALUE;
-        }
-    }
-
     private final class EntryIterator extends 
AbstractLazyIterator<PermissionEntry> {
 
         private final EntryPredicate predicate;

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AbstractGroupPrincipal.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AbstractGroupPrincipal.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AbstractGroupPrincipal.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/AbstractGroupPrincipal.java
 Thu Aug 18 13:15:22 2016
@@ -44,6 +44,10 @@ abstract class AbstractGroupPrincipal ex
         super(principalName, groupTree, namePathMapper);
     }
 
+    AbstractGroupPrincipal(@Nonnull String principalName, @Nonnull String 
groupPath, @Nonnull NamePathMapper namePathMapper) {
+        super(principalName, groupPath, namePathMapper);
+    }
+
     abstract UserManager getUserManager();
 
     abstract boolean isEveryone() throws RepositoryException;

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImpl.java
 Thu Aug 18 13:15:22 2016
@@ -25,6 +25,7 @@ import java.util.Set;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
+import com.google.common.collect.ImmutableList;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Properties;
@@ -105,7 +106,13 @@ import org.apache.jackrabbit.oak.spi.xml
         @Property(name = UserConstants.PARAM_PASSWORD_INITIAL_CHANGE,
                 label = "Change Password On First Login",
                 description = "When enabled, forces users to change their 
password upon first login.",
-                boolValue = UserConstants.DEFAULT_PASSWORD_INITIAL_CHANGE)
+                boolValue = UserConstants.DEFAULT_PASSWORD_INITIAL_CHANGE),
+        @Property(name = UserPrincipalProvider.PARAM_CACHE_EXPIRATION,
+                label = "Principal Cache Expiration",
+                description = "Optional configuration defining the number of 
milliseconds " +
+                        "until the principal cache expires (NOTE: currently 
only respected for principal resolution with the internal system session such 
as used for login). " +
+                        "If not set or equal/lower than zero no caches are 
created/evaluated.",
+                longValue = UserPrincipalProvider.EXPIRATION_NO_CACHE)
 })
 public class UserConfigurationImpl extends ConfigurationBase implements 
UserConfiguration, SecurityConfiguration {
 
@@ -158,7 +165,7 @@ public class UserConfigurationImpl exten
     @Nonnull
     @Override
     public List<? extends ValidatorProvider> getValidators(@Nonnull String 
workspaceName, @Nonnull Set<Principal> principals, @Nonnull MoveTracker 
moveTracker) {
-        return Collections.singletonList(new 
UserValidatorProvider(getParameters()));
+        return ImmutableList.of(new UserValidatorProvider(getParameters()), 
new CacheValidatorProvider(principals));
     }
 
     @Nonnull

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImporter.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImporter.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImporter.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserImporter.java
 Thu Aug 18 13:15:22 2016
@@ -323,31 +323,36 @@ class UserImporter implements ProtectedP
 
     @Override
     public void propertiesCompleted(@Nonnull Tree protectedParent) throws 
RepositoryException {
-        Authorizable a = userManager.getAuthorizable(protectedParent);
-        if (a == null) {
-            // not an authorizable
-            return;
-        }
-
-        // make sure the authorizable ID property is always set even if the
-        // authorizable defined by the imported XML didn't provide 
rep:authorizableID
-        if (!protectedParent.hasProperty(REP_AUTHORIZABLE_ID)) {
-            protectedParent.setProperty(REP_AUTHORIZABLE_ID, a.getID(), 
Type.STRING);
-        }
-
-        /*
-        Execute authorizable actions for a NEW user at this point after
-        having set the password and the principal name (all protected 
properties
-        have been processed now).
-        */
-        if (protectedParent.getStatus() == Tree.Status.NEW) {
-            if (a.isGroup()) {
-                userManager.onCreate((Group) a);
-            } else {
-                userManager.onCreate((User) a, currentPw);
+        if (isCacheNode(protectedParent)) {
+            // remove the cache if present
+            protectedParent.remove();
+        } else {
+            Authorizable a = userManager.getAuthorizable(protectedParent);
+            if (a == null) {
+                // not an authorizable
+                return;
+            }
+
+            // make sure the authorizable ID property is always set even if the
+            // authorizable defined by the imported XML didn't provide 
rep:authorizableID
+            if (!protectedParent.hasProperty(REP_AUTHORIZABLE_ID)) {
+                protectedParent.setProperty(REP_AUTHORIZABLE_ID, a.getID(), 
Type.STRING);
+            }
+
+            /*
+            Execute authorizable actions for a NEW user at this point after
+            having set the password and the principal name (all protected 
properties
+            have been processed now).
+            */
+            if (protectedParent.getStatus() == Tree.Status.NEW) {
+                if (a.isGroup()) {
+                    userManager.onCreate((Group) a);
+                } else {
+                    userManager.onCreate((User) a, currentPw);
+                }
             }
+            currentPw = null;
         }
-        currentPw = null;
     }
 
     @Override
@@ -507,6 +512,10 @@ class UserImporter implements ProtectedP
         return true;
     }
 
+    private static boolean isCacheNode(@Nonnull Tree tree) {
+        return tree.exists() && 
CacheConstants.REP_CACHE.equals(tree.getName()) && 
CacheConstants.NT_REP_CACHE.equals(TreeUtil.getPrimaryTypeName(tree));
+    }
+
     /**
      * Handling the import behavior
      *

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserPrincipalProvider.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserPrincipalProvider.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserPrincipalProvider.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/security/user/UserPrincipalProvider.java
 Thu Aug 18 13:15:22 2016
@@ -20,35 +20,44 @@ import java.security.Principal;
 import java.security.acl.Group;
 import java.text.ParseException;
 import java.util.Collections;
+import java.util.Date;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Set;
 import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import javax.jcr.AccessDeniedException;
 import javax.jcr.RepositoryException;
 
 import com.google.common.base.Function;
+import com.google.common.base.Joiner;
 import com.google.common.base.Predicate;
 import com.google.common.base.Predicates;
+import com.google.common.collect.Iterables;
 import com.google.common.collect.Iterators;
 import org.apache.jackrabbit.api.security.principal.PrincipalManager;
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
 import org.apache.jackrabbit.oak.api.PropertyState;
 import org.apache.jackrabbit.oak.api.Result;
 import org.apache.jackrabbit.oak.api.ResultRow;
 import org.apache.jackrabbit.oak.api.Root;
 import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.commons.LongUtils;
 import org.apache.jackrabbit.oak.namepath.NamePathMapper;
 import org.apache.jackrabbit.oak.security.user.query.QueryUtil;
 import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal;
 import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
 import org.apache.jackrabbit.oak.spi.security.principal.PrincipalProvider;
+import org.apache.jackrabbit.oak.spi.security.principal.SystemPrincipal;
 import org.apache.jackrabbit.oak.spi.security.user.AuthorizableType;
 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.UserUtil;
+import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.apache.jackrabbit.util.Text;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -64,6 +73,11 @@ class UserPrincipalProvider implements P
 
     private static final Logger log = 
LoggerFactory.getLogger(UserPrincipalProvider.class);
 
+    static final String PARAM_CACHE_EXPIRATION = "cacheExpiration";
+    static final long EXPIRATION_NO_CACHE = 0;
+
+    private static final long MEMBERSHIP_THRESHOLD = 0;
+
     private final Root root;
     private final UserConfiguration config;
     private final NamePathMapper namePathMapper;
@@ -71,6 +85,9 @@ class UserPrincipalProvider implements P
     private final UserProvider userProvider;
     private final MembershipProvider membershipProvider;
 
+    private final long expiration;
+    private final boolean cacheEnabled;
+
     UserPrincipalProvider(@Nonnull Root root,
                           @Nonnull UserConfiguration userConfiguration,
                           @Nonnull NamePathMapper namePathMapper) {
@@ -80,6 +97,9 @@ class UserPrincipalProvider implements P
 
         this.userProvider = new UserProvider(root, config.getParameters());
         this.membershipProvider = new MembershipProvider(root, 
config.getParameters());
+
+        expiration = 
config.getParameters().getConfigValue(PARAM_CACHE_EXPIRATION, 
EXPIRATION_NO_CACHE);
+        cacheEnabled = (expiration > EXPIRATION_NO_CACHE && 
root.getContentSession().getAuthInfo().getPrincipals().contains(SystemPrincipal.INSTANCE));
     }
 
     //--------------------------------------------------< PrincipalProvider 
>---
@@ -219,23 +239,108 @@ class UserPrincipalProvider implements P
 
     @Nonnull
     private Set<Group> getGroupMembership(@Nonnull Tree authorizableTree) {
-        Set<Group> groupPrincipals = new HashSet<Group>();
-        Iterator<String> groupPaths = 
membershipProvider.getMembership(authorizableTree, true);
-        while (groupPaths.hasNext()) {
-            Tree groupTree = 
userProvider.getAuthorizableByPath(groupPaths.next());
-            if (groupTree != null && UserUtil.isType(groupTree, 
AuthorizableType.GROUP)) {
-                Group gr = createGroupPrincipal(groupTree);
-                if (gr != null) {
-                    groupPrincipals.add(createGroupPrincipal(groupTree));
+        Set<Group> groupPrincipals = null;
+        NodeUtil authorizableNode = new NodeUtil(authorizableTree);
+        boolean doCache = cacheEnabled && UserUtil.isType(authorizableTree, 
AuthorizableType.USER);
+        if (doCache) {
+            groupPrincipals = readGroupsFromCache(authorizableNode);
+        }
+
+        // caching not configured or cache expired: use the membershipProvider 
to calculate
+        if (groupPrincipals == null) {
+            groupPrincipals = new HashSet<Group>();
+            Iterator<String> groupPaths = 
membershipProvider.getMembership(authorizableTree, true);
+            while (groupPaths.hasNext()) {
+                Tree groupTree = 
userProvider.getAuthorizableByPath(groupPaths.next());
+                if (groupTree != null && UserUtil.isType(groupTree, 
AuthorizableType.GROUP)) {
+                    Group gr = createGroupPrincipal(groupTree);
+                    if (gr != null) {
+                        groupPrincipals.add(createGroupPrincipal(groupTree));
+                    }
                 }
             }
+
+            // remember the regular groups in case caching is enabled
+            if (doCache) {
+                cacheGroups(authorizableNode, groupPrincipals);
+            }
         }
+
         // add the dynamic everyone principal group which is not included in
         // the 'getMembership' call.
         groupPrincipals.add(EveryonePrincipal.getInstance());
         return groupPrincipals;
     }
 
+    private void cacheGroups(@Nonnull NodeUtil authorizableNode, @Nonnull 
Set<Group> groupPrincipals) {
+        try {
+            root.refresh();
+            NodeUtil cache = 
authorizableNode.getChild(CacheConstants.REP_CACHE);
+            if (cache == null) {
+                if (groupPrincipals.size() <= MEMBERSHIP_THRESHOLD) {
+                    log.debug("Omit cache creation for user without group 
membership at " + authorizableNode.getTree().getPath());
+                    return;
+                } else {
+                    log.debug("Create new group membership cache at " + 
authorizableNode.getTree().getPath());
+                    cache = 
authorizableNode.addChild(CacheConstants.REP_CACHE, 
CacheConstants.NT_REP_CACHE);
+                }
+            }
+
+            cache.setLong(CacheConstants.REP_EXPIRATION, 
LongUtils.calculateExpirationTime(expiration));
+            String value = (groupPrincipals.isEmpty()) ? "" : 
Joiner.on(",").join(Iterables.transform(groupPrincipals, new Function<Group, 
String>() {
+                @Override
+                public String apply(Group input) {
+                    return Text.escape(input.getName());
+                }
+            }));
+            cache.setString(CacheConstants.REP_GROUP_PRINCIPAL_NAMES, value);
+
+            root.commit(CacheValidatorProvider.asCommitAttributes());
+            log.debug("Cached group membership at " + 
authorizableNode.getTree().getPath());
+
+        } catch (AccessDeniedException e) {
+            log.debug("Failed to cache group membership", e.getMessage());
+        } catch (CommitFailedException e) {
+            log.debug("Failed to cache group membership", e.getMessage(), e);
+        } finally {
+            root.refresh();
+        }
+    }
+
+    @CheckForNull
+    private Set<Group> readGroupsFromCache(@Nonnull NodeUtil authorizableNode) 
{
+        NodeUtil principalCache = 
authorizableNode.getChild(CacheConstants.REP_CACHE);
+        if (principalCache == null) {
+            log.debug("No group cache at " + 
authorizableNode.getTree().getPath());
+            return null;
+        }
+
+        if (isValidCache(principalCache)) {
+            log.debug("Reading group membership at " + 
authorizableNode.getTree().getPath());
+
+            String str = 
principalCache.getString(CacheConstants.REP_GROUP_PRINCIPAL_NAMES, null);
+            if (str == null || str.isEmpty()) {
+                return new HashSet<Group>(1);
+            }
+
+            Set<Group> groups = new HashSet<Group>();
+            for (String s : Text.explode(str, ',')) {
+                final String name = Text.unescape(s);
+                groups.add(new CachedGroupPrincipal(name));
+            }
+            return groups;
+        } else {
+            log.debug("Expired group cache for " + 
authorizableNode.getTree().getPath());
+            return null;
+        }
+    }
+
+    private static boolean isValidCache(NodeUtil principalCache)  {
+        long expirationTime = 
principalCache.getLong(CacheConstants.REP_EXPIRATION, EXPIRATION_NO_CACHE);
+        long now = new Date().getTime();
+        return expirationTime > EXPIRATION_NO_CACHE && now < expirationTime;
+    }
+
     private static String buildSearchPattern(String nameHint) {
         if (nameHint == null) {
             return "%";
@@ -246,7 +351,6 @@ class UserPrincipalProvider implements P
             sb.append('%');
             return sb.toString();
         }
-
     }
 
     private static boolean matchesEveryone(String nameHint, int searchType) {
@@ -288,19 +392,22 @@ class UserPrincipalProvider implements P
         }
     }
 
-    /**
-     * Implementation of {@link AbstractGroupPrincipal} that reads the 
underlying
-     * authorizable group lazily in case the group membership must be 
retrieved.
-     */
-    private final class GroupPrincipal extends AbstractGroupPrincipal {
+    
//--------------------------------------------------------------------------
+    // Group Principal implementations that retrieve member information on 
demand
+    
//--------------------------------------------------------------------------
+
+    private abstract class BaseGroupPrincipal extends AbstractGroupPrincipal {
 
         private UserManager userManager;
-        private org.apache.jackrabbit.api.security.user.Group group;
 
-        GroupPrincipal(@Nonnull String principalName, @Nonnull Tree groupTree) 
{
+        BaseGroupPrincipal(@Nonnull String principalName, @Nonnull Tree 
groupTree) {
             super(principalName, groupTree, namePathMapper);
         }
 
+        BaseGroupPrincipal(@Nonnull String principalName, @Nonnull String 
groupPath) {
+            super(principalName, groupPath, namePathMapper);
+        }
+
         @Override
         UserManager getUserManager() {
             if (userManager == null) {
@@ -327,7 +434,25 @@ class UserPrincipalProvider implements P
             return (g == null) ? Iterators.<Authorizable>emptyIterator() : 
g.getMembers();
         }
 
-        private org.apache.jackrabbit.api.security.user.Group getGroup() 
throws RepositoryException {
+        @CheckForNull
+        abstract org.apache.jackrabbit.api.security.user.Group 
getGroup()throws RepositoryException;
+    }
+
+    /**
+     * Implementation of {@link AbstractGroupPrincipal} that reads the 
underlying
+     * authorizable group lazily in case the group membership must be 
retrieved.
+     */
+    private final class GroupPrincipal extends BaseGroupPrincipal {
+
+        private org.apache.jackrabbit.api.security.user.Group group;
+
+        GroupPrincipal(@Nonnull String principalName, @Nonnull Tree groupTree) 
{
+            super(principalName, groupTree);
+        }
+
+        @Override
+        @CheckForNull
+        org.apache.jackrabbit.api.security.user.Group getGroup() throws 
RepositoryException {
             if (group == null) {
                 Authorizable authorizable = 
getUserManager().getAuthorizable(this);
                 if (authorizable != null && authorizable.isGroup()) {
@@ -337,4 +462,44 @@ class UserPrincipalProvider implements P
             return group;
         }
     }
+
+    private final class CachedGroupPrincipal extends BaseGroupPrincipal {
+
+        private org.apache.jackrabbit.api.security.user.Group group;
+
+        CachedGroupPrincipal(@Nonnull String principalName) {
+            super(principalName, "");
+        }
+
+        @Override
+        String getOakPath() {
+            String groupPath = getPath();
+            return (groupPath == null) ? null : 
namePathMapper.getOakPath(getPath());
+        }
+
+        @Override
+        public String getPath() {
+            try {
+                org.apache.jackrabbit.api.security.user.Group gr = getGroup();
+                return (gr == null) ? null : gr.getPath();
+            } catch (RepositoryException e) {
+                log.error("Failed to retrieve path from group principal", 
e.getMessage());
+                return null;
+            }
+        }
+
+        @Override
+        @CheckForNull
+        org.apache.jackrabbit.api.security.user.Group getGroup() throws 
RepositoryException {
+            if (group == null) {
+                Authorizable authorizable = 
getUserManager().getAuthorizable(new PrincipalImpl(getName()));
+                if (authorizable != null && authorizable.isGroup()) {
+                    group = (org.apache.jackrabbit.api.security.user.Group) 
authorizable;
+                }
+            }
+            return group;
+        }
+    }
 }
+
+

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/spi/security/CompositeConfiguration.java
 Thu Aug 18 13:15:22 2016
@@ -23,6 +23,7 @@ import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CopyOnWriteArrayList;
 
+import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
 
 import com.google.common.base.Function;
@@ -73,6 +74,11 @@ public abstract class CompositeConfigura
         this.securityProvider = securityProvider;
     }
 
+    @CheckForNull
+    public T getDefaultConfig() {
+        return defaultConfig;
+    }
+
     public void setDefaultConfig(@Nonnull T defaultConfig) {
         this.defaultConfig = defaultConfig;
     }

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/util/NodeUtil.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/util/NodeUtil.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/util/NodeUtil.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/util/NodeUtil.java
 Thu Aug 18 13:15:22 2016
@@ -238,6 +238,10 @@ public class NodeUtil {
         }
     }
 
+    public void setLong(@Nonnull String name, long value) {
+        tree.setProperty(name, value);
+    }
+
     public void setValues(String name, Value[] values) {
         try {
             tree.setProperty(PropertyStates.createProperty(name, 
Arrays.asList(values)));

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/util/package-info.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/util/package-info.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/util/package-info.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/java/org/apache/jackrabbit/oak/util/package-info.java
 Thu Aug 18 13:15:22 2016
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-@Version("1.0")
+@Version("1.1.0")
 @Export(optional = "provide:=true")
 package org.apache.jackrabbit.oak.util;
 

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
 Thu Aug 18 13:15:22 2016
@@ -287,6 +287,17 @@
  - * (UNDEFINED) IGNORE
  + * (nt:base) = rep:Unstructured IGNORE
 
+/**
+ * Unstructured base node type for protected repository internal information
+ * that is protected and must not be copied to the version store OPV
+ *
+ * @since oak 1.4
+ */
+[rep:UnstructuredProtected] abstract
+- * (UNDEFINED) protected multiple IGNORE
+- * (UNDEFINED) protected IGNORE
++ * (rep:UnstructuredProtected) protected IGNORE
+
 
//------------------------------------------------------------------------------
 // R E F E R E N C E A B L E
 
//------------------------------------------------------------------------------
@@ -754,6 +765,12 @@
 [rep:MemberReferencesList]
   + * (rep:MemberReferences) = rep:MemberReferences protected COPY
 
+/**
+ * @since oak 1.4
+ */
+[rep:Cache] > rep:UnstructuredProtected
+  - rep:expiration (LONG) protected IGNORE
+
 // 
-----------------------------------------------------------------------------
 // Privilege Management
 // 
-----------------------------------------------------------------------------

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/AbstractSecurityTest.java
 Thu Aug 18 13:15:22 2016
@@ -22,6 +22,7 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.UUID;
 
+import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import javax.jcr.Credentials;
 import javax.jcr.NoSuchWorkspaceException;
@@ -115,6 +116,10 @@ public abstract class AbstractSecurityTe
         }
     }
 
+    protected ContentRepository getContentRepository() {
+        return contentRepository;
+    }
+
     protected SecurityProvider getSecurityProvider() {
         if (securityProvider == null) {
             securityProvider = new 
SecurityProviderImpl(getSecurityConfigParameters());
@@ -194,6 +199,10 @@ public abstract class AbstractSecurityTe
     }
 
     protected ValueFactory getValueFactory() {
+        return getValueFactory(root);
+    }
+
+    protected ValueFactory getValueFactory(@Nonnull Root root) {
         return new ValueFactoryImpl(root, getNamePathMapper());
     }
 

Modified: 
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImplTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImplTest.java?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImplTest.java
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-core/src/test/java/org/apache/jackrabbit/oak/security/user/UserConfigurationImplTest.java
 Thu Aug 18 13:15:22 2016
@@ -16,9 +16,15 @@
  */
 package org.apache.jackrabbit.oak.security.user;
 
+import java.security.Principal;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 
+import com.google.common.collect.Lists;
 import org.apache.jackrabbit.oak.AbstractSecurityTest;
+import org.apache.jackrabbit.oak.spi.commit.MoveTracker;
+import org.apache.jackrabbit.oak.spi.commit.ValidatorProvider;
 import org.apache.jackrabbit.oak.spi.security.ConfigurationParameters;
 import org.apache.jackrabbit.oak.spi.security.user.UserConfiguration;
 import org.apache.jackrabbit.oak.spi.security.user.UserConstants;
@@ -28,6 +34,7 @@ import org.apache.jackrabbit.oak.spi.xml
 import org.junit.Test;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
 
 public class UserConfigurationImplTest extends AbstractSecurityTest {
 
@@ -48,6 +55,23 @@ public class UserConfigurationImplTest e
     }
 
     @Test
+    public void testValidators() {
+        UserConfigurationImpl configuration = new 
UserConfigurationImpl(getSecurityProvider());
+        List<? extends ValidatorProvider> validators = 
configuration.getValidators(adminSession.getWorkspaceName(), 
Collections.<Principal>emptySet(), new MoveTracker());
+        assertEquals(2, validators.size());
+
+        List<String> clNames = Lists.newArrayList(
+                UserValidatorProvider.class.getName(),
+                CacheValidatorProvider.class.getName());
+
+        for (ValidatorProvider vp : validators) {
+            clNames.remove(vp.getClass().getName());
+        }
+
+        assertTrue(clNames.isEmpty());
+    }
+
+    @Test
     public void testUserConfigurationWithConstructor() throws Exception {
         UserConfigurationImpl userConfiguration = new 
UserConfigurationImpl(getSecurityProvider());
         testConfigurationParameters(userConfiguration.getParameters());

Modified: 
jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication.md
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication.md?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication.md
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication.md
 Thu Aug 18 13:15:22 2016
@@ -76,7 +76,8 @@ LoginModule is configured and succeeds,
 LoginModule need to have succeeded for the overall authentication to succeed. 
If no Required or Requisite LoginModules 
 are configured for an application, then at least one Sufficient or Optional 
LoginModule must succeed.
 
-### JCR Authentication
+<a name="jcr_api"/>
+### JCR API
 
 Within the scope of JCR `Repository.login` is used to authenticate a given 
user.
 This method either takes a `Credentials` argument if the validation is 
performed
@@ -103,10 +104,8 @@ for further details.
 In addition JCR defines `Session.impersonate(Credentials)` to impersonate 
another
 user or - as of JSR 333 -  clone an existing session.
 
-
-### Oak Authentication
-
-#### Oak API
+<a name="oak_api"/>
+### Oak API
 
 The Oak API contains the following authentication related methods and 
interfaces
 
@@ -114,212 +113,7 @@ The Oak API contains the following authe
 - `ContentRepository.login(Credentials, String)`: The Oak counterpart of the 
JCR login.
 - `ContentSession.getAuthInfo()`: exposes the `AuthInfo` associated with the 
`ContentSession`.
 
-
-#### Differences wrt Jackrabbit 2.x
-
-See section [differences](authentication/differences.html) for complete list of
-differences wrt authentication between Jackrabbit 2.x and Oak.
-
-#### Guest Login
-
-The proper way to obtain an guest session as of Oak is as specified by JSR 283:
-
-    String wspName = null;
-    Session anonymous = repository.login(new GuestCredentials(), wspName);
-
-As of Oak 1.0 `Repository#login()` and `Repository#login(null, wspName)` is no
-longer treated as guest login. This behavior of Jackrabbit-core is violating 
the
-specification, which defines that null-login should be used for those cases 
where
-the authentication process is handled outside of the repository (see 
[Pre-Authentication](authentication/preauthentication.html)).
-
-Similarly, any special treatment that Jackrabbit core applied for the guest 
(anonymous)
-user has been omitted altogether from the default [LoginModuleImpl]. In the 
default
-setup the built-in anonymous user will be created without any password. 
Therefore
-explicitly uid/pw login using the anonymous userId will no longer work. This 
behavior
-is now consistent with the default login of any other user which doesn't have a
-password set.
-
-##### Guest Login Module
-
-The aim of the [GuestLoginModule] implementation is to provide backwards 
compatibility
-with Jackrabbit 2.x with respect to the guest (anonymous) login: the 
`GuestLoginModule`
-can be added as _optional_ entry to the chain of login modules in the JAAS (or
-corresponding OSGi) configuration.
-
-Example JAAS Configuration:
-
-    jackrabbit.oak {
-       org.apache.jackrabbit.oak.spi.security.authentication.GuestLoginModule  
optional;
-       org.apache.jackrabbit.oak.security.authentication.user.LoginModuleImpl 
required;
-    };
-
-
-The behavior of the `GuestLoginModule` is as follows:
-
-*Phase 1: Login*
-
-- tries to retrieve JCR credentials from the [CallbackHandler] using the 
[CredentialsCallback]
-- in case no credentials could be obtained it pushes a new instance of 
[GuestCredentials] to the shared stated
-  and **returns** `true`
-- otherwise it **returns** `false`
-
-*Phase 2: Commit*
-
-- if the phase 1 succeeded it will add the `GuestCredentials` created above and
-  `EveryonePrincipal` the `Subject` in phase 2 of the login process and 
**returns** `true`
-- otherwise it **returns** `false`
-
-#### UserId/Password Login
-
-Oak 1.0 comes with 2 different login module implementations that can handle
-`SimpleCredentials`:
-
-- Default (`LoginModuleImpl`) as described below
-- `ExternalLoginModule` as described in section [External 
Authentication](authentication/externalloginmodule.html)
-
-##### Default Login Module
-
-The [LoginModuleImpl] defines a regular userId/password login and requires a
-repository setup that supports [User Management](user.html) and is designed to
-supports the following `Credentials`:
-
-- `SimpleCredentials`
-- `GuestCredentials` (see above)
-- `ImpersonationCredentials` (see below)
-
-This login module implementations behaves as follows:
-
-*Phase 1: Login*
-
-* if a user does not exist in the repository (i.e. cannot be provided by the 
user manager) it **returns `false`**.
-* if an authorizable with the respective userId exists but is a group or a 
disabled users, it **throws `LoginException`**
-* if a user exists in the repository and the credentials don't match, it 
**throws `LoginException`**
-* if a user exists in the repository and the credentials match, it **returns 
`true`**
-    * also, it adds the credentials to the shared state
-    * also, it adds the login name to the shared state
-    * also, it calculates the principals and adds them to the private state
-    * also, it adds the credentials to the private state
-
-*Phase 2: Commit*
-
-* if the private state contains the credentials and principals, it adds them 
(both) to the subject and **returns `true`**
-* if the private state does not contain credentials and principals, it clears 
the state and **returns `false`**
-
-#### Impersonation
-
-Another flavor of the Oak authentication implementation is covered by
-`javax.jcr.Session#impersonate(Credentials)`, which allows to obtain an new
-`Session` for user identitified by the specified credentials. As of JSR 333
-this method can also be used in order to clone the existing session (i.e.
-self-impersonation of the user that holds the session.
-
-With Oak 1.0 impersonation is implemented as follows:
-
-1. `Session#impersonate` takes any kind of `Credentials`
-2. the specified credentials are wrapped in a new instance of 
[ImpersonationCredentials]
-   along with the current `AuthInfo` object.
-3. these `ImpersonationCredentials` are passed to `Repository.login`
-
-Whether or not impersonation succeeds consequently both depends on the 
authentication
-setup and on some implementation specific validation that make sure the
-editing session is allowed to impersonate the user identified by the 
credentials
-passed to the impersonate call.
-
-With Oak 1.0 only the default login module ([LoginModuleImpl]) is able to deal
-with `ImpersonationCredentials` and applies the following logic:
-
-- **Self-Impersonation**: Any attempt to impersonate the same session will 
succeed
-  as long as the user is still valid (i.e. exists and has not been disabled).
-- **Regular Impersonation**: Impersonation another user will only succeed if
-  the impersonated user is valid (i.e. exists and is not disabled) _and_ the
-  the user associated with the editing session is allowed to impersonate this
-  user. The latter depends on the [User Management](user.html) implementation
-  specifically on the return value of `User.getImpersonation().allows(Subject 
subject)`.
-
-##### ImpersonationCredentials
-
-Since the implementation of `Session.impersonate` no longer uses 
`SimpleCredentials`
-to transport the original `Subject` but rather performs the login with 
dedicated
-[ImpersonationCredentials], impersonation is no longer restricted to 
`SimpleCredentials`
-being passed to `Session#impersonate` call. Instead the specified credentials 
are
-passed to a new instance of `ImpersonationCredentials` delegating the 
evaluation
-and validation of the specified `Credentials` to the configured login 
module(s).
-
-This modification will not affect applications that used JCR API to impersonate
-a given session. Note however that applications relying on the Jackrabbit
-implementation and manually creating `SimpleCredentials` with a
-`SecurityConstants.IMPERSONATOR_ATTRIBUTE`, would need to be refactor after
-migration to Oak.
-
-##### Impersonation with Custom Authentication Setup
-
-Applications that wish to use a custom authentication setup need to ensure the
-following steps in order to get JCR impersonation working:
-
-- Respect `ImpersonationCredentials` in the authentication setup.
-- Identify the impersonated from `ImpersonationCredentials.getBaseCredentials`
-  and verify if it can be authenticated.
-- Validate that the editing session is allowed to impersonate: The user 
associated
-  with the editing session can be identified by the [AuthInfo] obtained from
-  from `ImpersonationCredentials.getImpersonatorInfo()`.
-
-
-#### Token Login
-
-See section [Token Authentication](authentication/tokenmanagement.html) for 
details
-regarding token based authentication.
-
-##### Token Login Module
-
-The `TokenLoginModule` is in charge of creating new login tokens and validate
-repository logins with `TokenCredentials`. The exact behavior of this login 
module is
-described in section [Token 
Authentication](authentication/tokenmanagement.html).
-
-
-#### Pre-Authenticated Login
-
-Oak provides two different mechanisms to create pre-authentication that doesn't
-involve the repositories internal authentication mechanism for credentials
-validation.
-
-- Pre-Authentication combined with Login Module Chain
-- Pre-Authentication without Repository Involvement (aka `null` login)
-
-See section [Pre-Authentication Login](authentication/preauthentication.html) 
for
-further details and examples.
-
-#### External Login
-
-While the default setup in Oak is solely relying on repository functionality to
-ensure proper authentication it quite common to authenticate against different
-systems (e.g. LDAP). For those setups that wish to combine initial 
authentication
-against a third party system with repository functionality, Oak provides a 
default
-implementation with extension points:
-
-- [External Authentication](authentication/externalloginmodule.html): Summary 
of
-  the external authentication and details about the `ExternalLoginModule`.
-- [User and Group Synchronization](authentication/usersync.html): Details 
regarding
-  user and group synchronization as well as a list of configuration options 
provided
-  by the the default implementations present with Oak.
-- [Identity Management](authentication/identitymanagement.html): Further 
information regarding extenal identity management.
-- [LDAP Integration](authentication/ldap.html): How to make use of the 
`ExternalLoginModule`
-  with the LDAP identity provider implementation. This combination is aimed to 
replace
-  [com.day.crx.security.ldap.LDAPLoginModule], which relies on Jackrabbit 
internals
-  and will no longer work with Oak.
-
-##### External Login Module
-
-The external login module is a base implementation that allows easy integration
-of 3rd party authentication and identity systems, such as [LDAP](ldap.html). 
The
-general mode of the external login module is to use the external system as 
authentication
-source and as a provider for users and groups that may also be synchronized 
into
-the repository.
-
-This login module implementation requires an valid `SyncHandler` and 
`IdentityProvider`
-to be present. The detailed behavior of the `ExternalLoginModule` is described 
in
-section [External Authentication](authentication/externalloginmodule.html).
-
-
+<a name="api_extensions"/>
 ### API Extension
 
 #### Oak Authentication
@@ -344,7 +138,7 @@ security related interfaces (e.g. `Princ
 
 Subclasses are required to implement the following methods:
 
-- `getSupportedCredentials(): return a set of supported credential classes.
+- `getSupportedCredentials()`: return a set of supported credential classes. 
See also section [Supported Credentials](#supported_credentials)
 - `login()`: The login method defined by `LoginModule`
 - `commit()`: The commit method defined by `LoginModule`
 
@@ -391,40 +185,27 @@ Subclasses are required to implement the
         }
     }
 
+<a name="supported_credentials"/>
+#### Supported Credentials
 
+Since Oak 1.5.1 the extensions additionally contain a dedicated interface that
+eases the support for different `Credentials` in the package space 
+`org.apache.jackrabbit.oak.spi.security.authentication.credentials`:
+                                                   
+- [CredentialsSupport]: Interface definition exposing the set of supported 
`Credentials` classes and some common utility methods.
+- [SimpleCredentialsSupport]: Default implementation for the widely used 
`SimpleCredentials`
+
+<a name="default_implementation"/>
+### Oak Authentication Implementation
+
+A description of the various requirements covered by Oak by default as well
+as the characteristics of the corresponding implementations can be found in
+section [Authentication: Implementation Details].
 
+See section [differences](authentication/differences.html) for comprehensive 
list 
+of differences wrt authentication between Jackrabbit 2.x and Oak.
 
-#### Token Management
-
-See section [token management](authentication/tokenmanagement.html) for 
details.
-
-- `TokenConfiguration`: Interface to obtain a `TokenProvider` instance.
-- `TokenProvider`: Interface to manage login tokens.
-- `TokenInfo`: Information related to a login token and token validity.
-
-#### User and Group Synchronization
-
-See section [Synchronization](authentication/usersync.html) for details.
-
-- `SyncManager`: factory for the `SyncHandler`
-- `SyncHandler`: responsible for synchronizing users/groups from an 
`ExternalIdentityProvider` into the repository.
-- `SyncContext`: executes the synchronization
-- `SyncedIdentity`: represents a synchronized identity
-- `SyncResult`: the result of a sync operation
-
-#### External Identity Management
-
-Oak in addition provides interfaces to ease custom implementation of the 
external
-authentication with optional user/group synchronization to the repository.
-See section [identity management](authentication/identitymanagement.html) for 
details.
-
-- `ExternalIdentityProviderManager`: factory for the `ExternalIdentityProvider`
-- `ExternalIdentityProvider`: provides user/group information from a third 
party system.
-- `ExternalIdentity`: base interface for an external user/group
-    - `ExternalUser`
-    - `ExternalGroup`
-- `ExternalIdentityRef`: reference to an external user/group
-
+<a name="configuration"/>
 ### Configuration
 
 The configuration of the authentication setup is defined by the 
[AuthenticationConfiguration].
@@ -439,9 +220,10 @@ There also exists a utility class that a
 - `ConfigurationUtil#getDefaultConfiguration`: default OAK configuration 
supporting uid/pw login configures `LoginModuleImpl` only
 - `ConfigurationUtil#getJackrabbit2Configuration`: backwards compatible 
configuration that provides the functionality covered by jackrabbit-core 
DefaultLoginModule, namely:
     - `GuestLoginModule`: null login falls back to anonymous
-    - `TokenLoginModule`: covers token base authentication
+    - `TokenLoginModule`: covers token based authentication
     - `LoginModuleImpl`: covering regular uid/pw login
 
+<a name="pluggability"/>
 ### Pluggability
 
 The default security setup as present with Oak 1.0 is able to provide custom
@@ -455,16 +237,11 @@ implementation on various levels:
    login modules and their individual settings. In an OSGi-base setup is 
achieved
    by making the modules accessible to the framework and setting their 
execution
    order accordingly. In a Non-OSGi setup this is specified in the [JAAS 
config].
-3. The `LoginModuleImpl` uses `UserAuthentication`-implementations for 
performing
-   the authentication process. Which user-authentication implementation to use 
is
-   determined by the available `UserAuthenticationFactory`s which provide user-
-   authentication implementations if a given `UserConfiguration` is accepted.
-   Which user-authentication-factory is chosen depends on its OSGi service
-   ranking property. The default factory has a ranking of 0 (OSGi default). 
Services with
-   the highest ranking take precedence.
 
+<a name="further_reading"/>
 ### Further Reading
 
+- [Authentication: Implementation Details](authentication/default.html)
 - [Differences wrt Jackrabbit 2.x](authentication/differences.html)
 - [Token Authentication and Token 
Management](authentication/tokenmanagement.html)
 - [External Authentication](authentication/externalloginmodule.html)
@@ -480,12 +257,10 @@ implementation on various levels:
 [javax.jcr.SimpleCredentials]: 
http://www.day.com/specs/javax.jcr/javadocs/jcr-2.0/javax/jcr/SimpleCredentials.html
 [javax.jcr.Repository]: 
http://www.day.com/specs/javax.jcr/javadocs/jcr-2.0/javax/jcr/Repository.html
 [org.apache.jackrabbit.api.JackrabbitRepository]: 
http://svn.apache.org/repos/asf/jackrabbit/trunk/jackrabbit-api/src/main/java/org/apache/jackrabbit/api/JackrabbitRepository.java
-[ImpersonationCredentials]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/ImpersonationCredentials.html
 [AuthInfoImpl]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/AuthInfoImpl.html
 [AuthInfo]: /oak/docs/apidocs/org/apache/jackrabbit/oak/api/AuthInfo.html
-[GuestLoginModule]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/GuestLoginModule.html
-[LoginModuleImpl]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/security/authentication/user/LoginModuleImpl.html
-[com.day.crx.security.ldap.LDAPLoginModule]: 
http://dev.day.com/docs/en/crx/current/administering/ldap_authentication.html
+[AbstractLoginModule]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModule.html
 [AuthenticationConfiguration]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/AuthenticationConfiguration.html
-[AbstractLoginModoule]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/AbstractLoginModule.html
-[JAAS config]: 
http://docs.oracle.com/javase/6/docs/technotes/guides/security/jaas/JAASRefGuide.html
\ No newline at end of file
+[JAAS config]: 
http://docs.oracle.com/javase/6/docs/technotes/guides/security/jaas/JAASRefGuide.html
+[CredentialsSupport]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/credentials/CredentialsSupport.html
+[SimpleCredentialsSupport]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/credentials/SimpleCredentialsSupport.html

Copied: 
jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication/defaultusersync.md
 (from r1740250, 
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/defaultusersync.md)
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication/defaultusersync.md?p2=jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication/defaultusersync.md&p1=jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/defaultusersync.md&r1=1740250&r2=1756777&rev=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-doc/src/site/markdown/security/authentication/defaultusersync.md
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication/defaultusersync.md
 Thu Aug 18 13:15:22 2016
@@ -18,25 +18,189 @@
 User and Group Synchronization : The Default Implementation
 
--------------------------------------------------------------------------------
 
-### DefaultSyncHandler
+### Default Implementation of Sync API
+
+#### SyncManager
+
+The default implementation (`SyncManagerImpl`) is intended for use in an 
OSGi-base
+repository setup: it tracks all `SyncHandler` registered via OSGi.
+
+It can be used in non-OSGi environments by passing a 
`org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard`
+to the constructor.
+
+#### SyncHandler
 
 The [DefaultSyncHandler] comes with a set of configuration options that
-allow to specify the synchronization behavior (see below). All users/groups
-synchronized by this handler will get the following properties set.
+allow to specify the synchronization behavior (see below). Depending on the 
+configuration it chooses between two different `SyncContext` implementations.
+
+#### SyncContext
+
+Oak provides the following implementations of the [SyncContext] interface:
 
+- [DefaultSyncContext]: base implementation that synchronizes external user 
and group accounts into the repository
+- [DynamicSyncContext]: derived implementation that provides special handling 
for external groups.
+ 
+##### DefaultSyncContext
+
+All users/groups synchronized by this context will get the following 
properties set.
 These properties allow to run separate task for periodical update and make sure
 the authorizables can later on be identified as external users.
 
 - `rep:externalId` : This allows to identify the external users, know the 
associated IDP and distinguish them from others.
 - `rep:lastSynced` : Sync timestamp to mark the external user/group valid for 
the configurable time (to reduce expensive syncing). Once expired, they will be 
validated against the 3rd party system again.
 
+The [DefaultSyncContext] is exported as part of the 'basic' package space and
+may be used to provide custom implementations.
+
+##### DynamicSyncContext
+
+Extending from the [DefaultSyncContext] this implementation that provides 
special 
+handling  for external groups in case the [Dynamic Group 
Membership](#dynamic_membership) 
+option is enabled in the [Configuration](#configuration).
+
+In addition to the properties mentioned above this implementation will 
additionally create 
+a multivalued STRING property that caches the group principal names of the 
external 
+user accounts:
+
+- `rep:externalPrincipalNames` : Optional system-maintained property related 
to [Dynamic Group Membership](#dynamic_membership)
+
+#### SyncResult
+
+The [DefaultSyncResultImpl] is exported as part of the 'basic' package space 
+providing a simple `SyncResult` implementation based on a status and a 
[DefaultSyncedIdentity].
+
+
+#### SyncedIdentity
+
+The [DefaultSyncedIdentity] is exported as part of the 'basic' package space. 
It 
+maps the ID of a synchronized user/group account to the external identity 
references
+represented by [ExternalIdentityRef].
+
+
+<a name="dynamic_membership"/>
+### Dynamic Group Membership
+
+As of Oak 1.5.3 the default sync handler comes with an addition configuration 
+option that allows to enable dynamic group membership resolution for external 
users. 
+Enabling dynamic membership in the [DefaultSyncConfig] will change the way 
external
+groups are synchronized (see also [OAK-4101]). 
+
+The key benefits of dynamic membership resolution are:
+
+- avoiding duplicate user management effort wrt to membership handling both in 
the external IDP and the repository
+- ease principal resolution upon repository login
+
+#### SyncContext with Dynamic Membership
+
+With the default `SyncHandler` this configuration option will show the 
following 
+effects:
+
+- If enabled the handler will use an alternative [SyncContext] to synchronize 
external groups.
+- Instead of synchronizing groups into the user management, this 
[DynamicSyncContext]
+  will additionally set the property `rep:externalPrincipalNames` on the 
synchronized external user
+- `rep:externalPrincipalNames` is a system maintained multivalued property of 
type 
+  'STRING' storing the names of the `java.security.acl.Group`-principals a 
given 
+  external user is member of (both declared and inherited according to the 
configured
+  membership nesting depth)
+- External groups will no longer be synchronised into the repository's user 
management 
+  but will only be available as `Principal`s (see section _User Management_ 
below).
+  
+#### Effect of Dynamic Membership on other Security Modules
+  
+##### Principal Management
+
+The dynamic (principal) membership features comes with a dedicated 
`PrincipalConfiguration` 
+implementation (i.e. [ExternalPrincipalConfiguration]) that is in charge of 
securing  
+the `rep:externalPrincipalNames` properties (see also section 
[Validation](#validation) 
+and [Configuration](#configuration) below). 
+
+Additionally the [ExternalPrincipalConfiguration] provides a 
`PrincipalProvider` 
+implementation which makes external (group) principals available to the 
repository's 
+authentication and authorization using the `rep:externalPrincipalNames` as a 
+persistent cache to avoid expensive lookup on the IDP.
+This also makes external `Principal`s retrievable and searchable through the 
+Jackrabbit principal management API (see section [Principal 
Management](../principal.html)
+for a comprehensive description).
+
+Please note the following implementation detail wrt accessibility of group 
principals:
+A given external principal will be accessible though the principal management 
API 
+if it can be read from any of the `rep:externalPrincipalNames` properties 
+present using a dedicated query.
+
+##### User Management
+
+As described above the dynamic membership option will effectively disable the
+synchronization of the complete external group account information into the 
repository's
+user management feature but limit the synchronized information to the 
principal 
+names and the membership relation between a given `java.security.acl.Group` 
principal 
+and external user accounts.
+
+The user management API will consequently no longer be knowledgeable of 
external 
+group identities (exception: groups that have been synchronized before 
enabling 
+the feature will remain untouched and will be synchronized according to the 
+sync configuration).
+
+While this behavior does not affect default authentication and authorization 
modules 
+(see below) it will have an impact on applications that rely on full 
synchronization 
+of external identities. Those application won't be able to benefit from the 
dynamic 
+membership feature until dynamic groups can be created with the 
+Jackrabbit [User Management API](../user.html) (see [OAK-2687]).
+
+##### Authentication
+
+The authentication setup provided by Oak is not affected by the dynamic 
membership 
+handling as long as the configured `LoginModule` implementations rely on the 
+`PrincipalProvider` for principal resolution and the 
[ExternalPrincipalConfiguration]
+is properly registered with the `SecurityProvider` (see section 
[Configuration](#configuration) below).
+
+##### Authorization
+
+The authorization modules shipped with Oak only depend on `Principal`s (and 
not on
+user management functionality) and are therefore not affected by the dynamic 
+membership configuration.
+
+<a name="xml_import"/>
+#### XML Import
+
+The protected nature of the `rep:externalPrincipalNames` is also reflected 
during
+XML import of user accounts:
+
+External users with a `rep:externalPrincipalNames` property will get regularly 
imported.
+However, any non-system driven import will omit the 
`rep:externalPrincipalNames` 
+and additional remove the `rep:lastSynced` property in order to force a re-sync
+of the external user by the system upon the next login or when triggered 
through
+the JMX console. Depending on the _User Dynamic Membership_ configuration 
value on
+the target system the sync will then result in a full sync of group membership 
or 
+will re-create the `rep:externalPrincipalNames` property.
+
+<a name="validation"/>
+#### Validation
+
+As of Oak 1.5.3 a dedicated `Validator` implementation asserts that the 
protected,
+system-maintained property `rep:externalPrincipalNames` is only written by the 
+internal system session. 
+
+This prevents users to unintentionally or maliciously manipulating the 
information
+linking to the external identity provider in particular their external identity
+and the set of external group principals associated with their account.
+
+Additionally the validator asserts the consistency of the properties defined
+with external user/group accounts.
+
+| Code              | Message                                                  
|
+|-------------------|----------------------------------------------------------|
+| 0070              | Attempt to create, modify or remove the system property 
rep:externalPrincipalNames |
+| 0071              | Attempt to write rep:externalPrincipalNames with a type 
other than Type.STRINGS |
+| 0072              | Property rep:externalPrincipalNames requires 
rep:externalId to be present on the Node. |
+| 0073              | Property rep:externalId cannot be removed if 
rep:externalPrincipalNames is present. |
 
 <a name="configuration"/>
 ### Configuration
 
 #### Configuration of the DefaultSyncHandler
 
-The default `SyncHandler` implementation is configured via [DefaultSyncConfig]:
+The default `SyncHandler` implementations are configured via 
[DefaultSyncConfig]:
 
 | Name                          | Property                      | Description  
                            |
 
|-------------------------------|-------------------------------|------------------------------------------|
@@ -45,6 +209,7 @@ The default `SyncHandler` implementation
 | User Expiration Time          | `user.expirationTime`         | Duration 
until a synced user gets expired (eg. '1h 30m' or '1d'). |
 | User Membership Expiration    | `user.membershipExpTime`      | Time after 
which membership expires (eg. '1h 30m' or '1d'). |
 | User membership nesting depth | `user.membershipNestingDepth` | Returns the 
maximum depth of group nesting when membership relations are synced. A value of 
0 effectively disables group membership lookup. A value of 1 only adds the 
direct groups of a user. This value has no effect when syncing individual 
groups only when syncing a users membership ancestry. |
+| User Dynamic Membership       | `user.dynamicMembership`      | Enabling 
dynamic membership for external users. |
 | User Path Prefix              | `user.pathPrefix`             | The path 
prefix used when creating new users. |
 | User property mapping         | `user.propertyMapping`        | List mapping 
definition of local properties from external ones. eg: 'profile/email=mail'.Use 
double quotes for fixed values. eg: 'profile/nt:primaryType="nt:unstructured" |
 | Group auto membership         | `group.autoMembership`        | List of 
groups that a synced group is added to automatically |
@@ -53,7 +218,28 @@ The default `SyncHandler` implementation
 | Group property mapping        | `group.propertyMapping`       | List mapping 
definition of local properties from external ones. |
 | | | |
 
+#### Configuration of the ExternalPrincipalConfiguration
+
+Please note that the [ExternalPrincipalConfiguration] comes with a dedicated
+`RepositoryInitializer`, which requires the repository to be (re)initialized
+once the module `oak-auth-external` is installed.
+
+The recommended way to assert a proper init, is to add 
+'org.apache.jackrabbit.oak.spi.security.authentication.external.impl.principal.ExternalPrincipalConfiguration'
+as additional value to the `requiredServicePids` configuration option of the 
+`SecurityProviderRegistration` _("Apache Jackrabbit Oak SecurityProvider")_.
+
+See section [Introduction to Oak Security](../introduction.html) for further 
details on the `SecurityProviderRegistration`.
 
 <!-- references -->
+[SyncContext]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncContext.html
+[DefaultSyncContext]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncContext.html
+[DefaultSyncConfig]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncConfig.html
+[DefaultSyncResultImpl]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncResultImpl.html
+[DefaultSyncedIdentity]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/DefaultSyncedIdentity.html
 [DefaultSyncHandler]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.html
-[DefaultSyncConfig]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfig.html
+[ExternalIdentityRef]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityRef.html
+[ExternalPrincipalConfiguration]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/ExternalPrincipalConfiguration.html
+[DynamicSyncContext]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/principal/DynamicSyncContext.html
+[OAK-4101]: https://issues.apache.org/jira/browse/OAK-4101
+[OAK-2687]: https://issues.apache.org/jira/browse/OAK-2687
\ No newline at end of file

Modified: 
jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication/externalloginmodule.md
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication/externalloginmodule.md?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication/externalloginmodule.md
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication/externalloginmodule.md
 Thu Aug 18 13:15:22 2016
@@ -36,7 +36,8 @@ what it does not:
 * provide a transparent oak principal provider.
 * offer services for background synchronization of users and groups
 
-### Structure
+<a name="details"/>
+### Implementation Details
 The external identity and login handling is split into 3 parts:
 
 - **External Login Module**: LoginModule implementation that represents the 
connection between JAAS login mechanism, the external identity provider and the 
synchronization handler.
@@ -62,14 +63,20 @@ If a user needs re-authentication (for e
 if the user is not yet present in the local system at all), the login module 
must
 check the credentials with the external system during the `login()` method.
 
-Note:
+The details of the default user/group synchronization mechanism are described 
in section
+[User and Group Synchronization : The Default 
Implementation](defaultusersync.html)
 
-* users (and groups) that are synced from the 3rd party system contain a 
`rep:externalId` property. This allows to identify the external users and 
distinguish them from others.
-* to reduce expensive syncing, the synced users and groups have sync timestamp 
`rep:lastSynced` and are considered valid for a configurable time. if they 
expire, they need to be validated against the 3rd party system again.
+##### Supported Credentials
 
-Current this login module supports the following credentials:
+As of Oak 1.5.1 the `ExternalLoginModule` can deal for any kind of 
`Credentials`
+implementations. By default (i.e. unless configured otherwise) the module 
supports
+`SimpleCredentials` and thus behaves backwards compatible to previous versions.
 
-- `SimpleCredentials`
+Additional/other credentials can be supported by providing an 
`ExternalIdentityProvider` 
+that additionally implements the [CredentialsSupport] interface.
+See section [Pluggability](#pluggability) for instructions and an example.
+
+##### Authentication in Detail 
 
 The details of the external authentication are as follows:
 
@@ -108,14 +115,32 @@ present on the IDP.
 See section [User Synchronization](usersync.html) for further details and a
 description of the default implementation.
 
+<a name="configuration"/>
 ### Configuration
 
+#### Configuration Parameters
+
+The external authentication module comes with the following configuration 
parameters
+for the [ExternalLoginModuleFactory]/[ExternalLoginModule].
+
+| Parameter                 | Type     | Default    | Description |
+|---------------------------|----------|------------|-------------|
+| `PARAM_IDP_NAME`          | String   | \-         | Name of the external IDP 
to be retrieved from the `ExternalIdentityProviderManager` |
+| `PARAM_SYNC_HANDLER_NAME` | String   | \-         | Name of the sync handler 
to be retrieved from the `SyncManager` |
+|                           |          |            |                          
|
+| _Optional (OSGi-setup)_   |          |            |                          
|
+| `JAAS_RANKING`            | int      | 50         | Ranking of the 
`ExternalLoginModule` in the JAAS configuration, see [LoginModuleFactory] |
+| `JAAS_CONTROL_FLAG`       | String   | SUFFICIENT | See 
[LoginModuleControlFlag] for supported values. |
+| `JAAS_REALM_NAME`         | String   | \-         | See [LoginModuleFactory] 
|
+
 ##### Examples
 
 ###### Example JAAS Configuration
 
 The following JAAS configuration shows how the `ExternalLoginModule` could be
-used in a setup that not solely uses third party login:
+used in a setup that not solely uses third party login (Note: JAAS 
configuration 
+equivalents of the parameters defined by 
`org.apache.felix.jaas.LoginModuleFactory` 
+are omitted):
 
     jackrabbit.oak {
          
org.apache.jackrabbit.oak.security.authentication.token.TokenLoginModule 
sufficient;
@@ -125,7 +150,105 @@ used in a setup that not solely uses thi
             idp.name="ldap";
      };
 
-<!-- references -->
+<a name="pluggability"/>
+### Pluggability
 
-[ExternalIdentityProvider]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityProvider.html
+The design of the `ExternalLoginModule` allows for customization of the key 
features
+associated with third party authentication. In an OSGi-based setup these are 
+covered by references within the `ExternalLoginModuleFactory`:
+
+ - [ExternalIdentityProviderManager]: Mandatory, unary reference for the 
`ExternalIdentityProvider` lookup; see [External Identity 
Management](identitymanagement.html) for details. 
+ - [SyncManager]: Mandatory, unary reference for the `SyncHandler` lookup; see 
[User/Group Synchronization](usersync.html) for details.
+
+The default implementations ([ExternalIDPManagerImpl] and [SyncManagerImpl]) 
+extend `AbstractServiceTracker` and will automatically keep track of 
+new [ExternalIdentityProvider] and [SyncHandler] services, respectively.
+
+Since Oak 1.5.1 support for different or multiple types of `Credentials` can 
easily
+be plugged by providing an [ExternalIdentityProvider] that additionally 
implements 
+[CredentialsSupport]. This is an optional extension point for each IDP; if 
+missing the `ExternalLoginModule` will fall back to a default implementation 
and 
+assume the IDP only supports `SimpleCredentials`. See details below.
+ 
+#### Supported Credentials
+ 
+The following steps are required in order to change or extend the set 
credential 
+classes supported by the `ExternalLoginModule`:
+
+- Extend your `ExternalIdentityProvider` to additionally implement the 
[CredentialsSupport] interface.
+
+Don't forget to make sure that 
`ExternalIdentityProvider.authenticate(Credentials)` 
+handles the same set of supported credentials!
+
+##### Examples
+ 
+###### Example CredentialsSupport
+
+      @Component()
+      @Service(ExternalIdentityProvider.class, CredentialsSupport.class)
+      public class MyIdentityProvider implements ExternalIdentityProvider, 
CredentialsSupport {
+    
+          public MyCredentialsSupport() {}
+    
+          //-----------------------------------------< CredentialsSupport >---
+          @Nonnull
+          @Override
+          public Set<Class> getCredentialClasses() {
+              return ImmutableSet.<Class>of(MyCredentials.class);
+          }
+  
+          @CheckForNull
+          @Override
+          public String getUserId(@Nonnull Credentials credentials) {
+              if (credentials instanceof MyCredentials) {
+                  return ((MyCredentials) credentials).getID();
+              } else {
+                  return null;
+              }
+          }
+  
+          @Nonnull
+          @Override
+          public Map<String, ?> getAttributes(@Nonnull Credentials 
credentials) {
+              // our credentials never contain additional attributes
+              return ImmutableMap.of();
+          }
+          
+          //-------------------------------------< ExternalIdentityProvider 
>---
+          
+          @CheckForNull
+          @Override
+          public ExternalUser authenticate(@Nonnull Credentials credentials) {
+              if (credentials instanceof MyCredentials) {
+                  MyCredentials mc = (MyCredentials) credentials;
+                  if (internalAuthenticate(mc)) {
+                      return new MyExternalUser(mc.getID());
+                  } else {
+                      throw new LoginException();
+                  }
+              } else {
+                  return null;
+              }
+          }
+    
+          [...]
+          
+          //----------------------------------------------< SCR Integration 
>---
+          @Activate
+          private void activate() {
+              // TODO
+          }
+      }
+
+<!-- references -->
 [DefaultSyncConfig]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfig.html
+[ExternalIdentityProvider]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityProvider.html
+[ExternalIdentityProviderManager]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalIdentityProviderManager.html
+[ExternalIDPManagerImpl]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalIDPManagerImpl.html
+[ExternalLoginModuleFactory]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.html
+[LoginModuleFactory]: 
http://svn.apache.org/repos/asf/felix/trunk/jaas/src/main/java/org/apache/felix/jaas/LoginModuleFactory.java
+[LoginModuleControlFlag]: 
https://docs.oracle.com/javase/7/docs/api/javax/security/auth/login/AppConfigurationEntry.LoginModuleControlFlag.html
+[SyncHandler]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncHandler.html
+[SyncManager]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncManager.html
+[SyncManagerImpl]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/SyncManagerImpl.html
+[CredentialsSupport]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/credentials/CredentialsSupport.html

Modified: 
jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication/usersync.md
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication/usersync.md?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- 
jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication/usersync.md
 (original)
+++ 
jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/authentication/usersync.md
 Thu Aug 18 13:15:22 2016
@@ -24,9 +24,6 @@ The synchronization of users and groups
 after a user is successfully authenticated against the IDP or if it's no longer
 present on the IDP.
 
-Oak comes with a default implementation of the `SyncHandler` interface:
-[org.apache.jackrabbit.oak.spi.security.authentication.external.impl.DefaultSyncHandler].
-
 ### Synchronization API
 
 - [SyncManager]: factory for all configured `SyncHandler` implementations.
@@ -52,39 +49,9 @@ for the following tasks:
 ### Default Implementation
 
 Oak 1.0 provides a default implementation of the user synchronization API that 
allow
-to plug additional `SyncHandler` implementations.
-
-The [DefaultSyncHandler] itself comes with a set of configuration options that
-allow to specify the synchronization behavior (see below). All users/groups
-synchronized by this handler will get the following properties set:
-
-- `rep:externalId`
-- `rep:lastSynced`
-
-These properties allow to run separat task for periodical update and make sure
-the authorizables can later on be identitied as external users.
-
-### Configuration
-
-#### Configuration of the DefaultSyncHandler
-
-The default sync handler implementation is configured via [DefaultSyncConfig]:
-
-| Name                          | Property                      | Description  
                            |
-|-------------------------------|-------------------------------|------------------------------------------|
-| Sync Handler Name             | `handler.name`                | Name of this 
sync configuration. This is used to reference this handler by the login 
modules. |
-| User auto membership          | `user.autoMembership`         | List of 
groups that a synced user is added to automatically |
-| User Expiration Time          | `user.expirationTime`         | Duration 
until a synced user gets expired (eg. '1h 30m' or '1d'). |
-| User Membership Expiration    | `user.membershipExpTime`      | Time after 
which membership expires (eg. '1h 30m' or '1d'). |
-| User membership nesting depth | `user.membershipNestingDepth` | Returns the 
maximum depth of group nesting when membership relations are synced. A value of 
0 effectively disables group membership lookup. A value of 1 only adds the 
direct groups of a user. This value has no effect when syncing individual 
groups only when syncing a users membership ancestry. |
-| User Path Prefix              | `user.pathPrefix`             | The path 
prefix used when creating new users. |
-| User property mapping         | `user.propertyMapping`        | List mapping 
definition of local properties from external ones. eg: 'profile/email=mail'.Use 
double quotes for fixed values. eg: 'profile/nt:primaryType="nt:unstructured" |
-| Group auto membership         | `group.autoMembership`        | List of 
groups that a synced group is added to automatically |
-| Group Expiration Time         | `group.expirationTime`        | Duration 
until a synced group expires (eg. '1h 30m' or '1d'). |
-| Group Path Prefix             | `group.pathPrefix`            | The path 
prefix used when creating new groups. |
-| Group property mapping        | `group.propertyMapping`       | List mapping 
definition of local properties from external ones. |
-| | | |
+to plug additional `SyncHandler` implementations. 
 
+Default implementation is described in section [User and Group Synchronization 
: The Default Implementation](defaultusersync.html).
 
 ### Pluggability
 
@@ -110,5 +77,3 @@ or plug a new implementation of the `Syn
 [SyncedIdentity]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncedIdentity.html
 [SyncResult]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncResult.html
 [SyncException]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncException.html
-[DefaultSyncHandler]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.html
-[DefaultSyncConfig]: 
/oak/docs/apidocs/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncConfig.html

Modified: 
jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/principal.md
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/principal.md?rev=1756777&r1=1756776&r2=1756777&view=diff
==============================================================================
--- jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/principal.md 
(original)
+++ jackrabbit/oak/branches/1.2/oak-doc/src/site/markdown/security/principal.md 
Thu Aug 18 13:15:22 2016
@@ -41,6 +41,9 @@ different sources.
 - [CompositePrincipalProvider]: Implementation that combines different 
principals
 from different source providers.
 
+See section [Implementations of the PrincipalProvider 
Interface](principal/principalprovider.html)
+for details.
+
 ##### Special Principals
 - [AdminPrincipal]: Marker interface to identify the principal associated with 
administrative user(s).
 - [EveryonePrincipal]: built-in group principal implementation that has every 
other valid principal as member.


Reply via email to