You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by dj...@apache.org on 2016/08/18 13:15:23 UTC

svn commit: r1756777 [3/4] - in /jackrabbit/oak/branches/1.2: ./ oak-auth-external/ oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/basic/ oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/secu...

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.