Author: tripod
Date: Wed Mar 12 01:15:05 2014
New Revision: 1576555

URL: http://svn.apache.org/r1576555
Log:
OAK-516 Create LdapLoginModule based on ExternalLoginModule (wip)

Added:
    
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncedIdentity.java
    jackrabbit/oak/trunk/oak-auth-external/src/test/scripts/
    jackrabbit/oak/trunk/oak-auth-external/src/test/scripts/generate_ldif.pl   
(with props)
    jackrabbit/oak/trunk/oak-auth-external/src/test/scripts/users.csv
Modified:
    jackrabbit/oak/trunk/oak-auth-external/pom.xml
    
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncContext.java
    
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncHandler.java
    
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.java
    
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java
    
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java
    
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java

Modified: jackrabbit/oak/trunk/oak-auth-external/pom.xml
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/pom.xml?rev=1576555&r1=1576554&r2=1576555&view=diff
==============================================================================
Binary files - no diff available.

Modified: 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncContext.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncContext.java?rev=1576555&r1=1576554&r2=1576555&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncContext.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncContext.java
 Wed Mar 12 01:15:05 2014
@@ -34,6 +34,16 @@ public interface SyncContext {
     boolean sync(@Nonnull ExternalIdentity identity) throws SyncException;
 
     /**
+     * Synchronizes an authorizable with the corresponding external identity 
with the repository based on the respective
+     * configuration.
+     *
+     * @param id the id of the authorizable
+     * @return {@code true} if the given identity was synced; {@code false} 
for no change.
+     * @throws SyncException if an error occurrs
+     */
+    boolean sync(@Nonnull String id) throws SyncException;
+
+    /**
      * Closes this context and releases any resources bound to it. Note that 
an implementation must not commit the
      * {@link org.apache.jackrabbit.oak.api.Root} passed during the creation 
call. This is the responsibility of the
      * application.

Modified: 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncHandler.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncHandler.java?rev=1576555&r1=1576554&r2=1576555&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncHandler.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncHandler.java
 Wed Mar 12 01:15:05 2014
@@ -16,7 +16,9 @@
  */
 package org.apache.jackrabbit.oak.spi.security.authentication.external;
 
+import javax.annotation.CheckForNull;
 import javax.annotation.Nonnull;
+import javax.jcr.RepositoryException;
 
 import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.jackrabbit.oak.api.Root;
@@ -55,4 +57,12 @@ public interface SyncHandler {
                               @Nonnull UserManager userManager,
                               @Nonnull Root root) throws SyncException;
 
+    /**
+     * Tries to find the identity with the given authorizable id or name.
+     * @param userManager the user manager
+     * @param id the id or name of the authorizable
+     * @return a synced identity object or {@code null}
+     */
+    @CheckForNull
+    SyncedIdentity findIdentity(@Nonnull UserManager userManager, @Nonnull 
String id) throws RepositoryException;
 }
\ No newline at end of file

Added: 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncedIdentity.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncedIdentity.java?rev=1576555&view=auto
==============================================================================
--- 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncedIdentity.java
 (added)
+++ 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/SyncedIdentity.java
 Wed Mar 12 01:15:05 2014
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jackrabbit.oak.spi.security.authentication.external;
+
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+
+/**
+ * Represents a synchronized identity managed by a {@link SyncHandler}.
+ */
+public interface SyncedIdentity {
+
+    /**
+     * Returns the internal id or name of the corresponding authorizable.
+     * @return the id.
+     */
+    @Nonnull
+    String getId();
+
+    /**
+     * Returns the external reference of this identity.
+     * @return the reference or {@code null}
+     */
+    @CheckForNull
+    ExternalIdentityRef getExternalIdRef();
+
+    /**
+     * Checks if this identity represents a group.
+     * @return {@code true} if group.
+     */
+    boolean isGroup();
+
+    /**
+     * Returns the time when this identity was last synced or a value less or 
equal to 0 if it was never synced.
+     * @return the time when this identity was last synced.
+     */
+    long lastSynced();
+}
\ No newline at end of file

Modified: 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.java?rev=1576555&r1=1576554&r2=1576555&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/DefaultSyncHandler.java
 Wed Mar 12 01:15:05 2014
@@ -59,6 +59,7 @@ import org.apache.jackrabbit.oak.spi.sec
 import 
org.apache.jackrabbit.oak.spi.security.authentication.external.SyncContext;
 import 
org.apache.jackrabbit.oak.spi.security.authentication.external.SyncException;
 import 
org.apache.jackrabbit.oak.spi.security.authentication.external.SyncHandler;
+import 
org.apache.jackrabbit.oak.spi.security.authentication.external.SyncedIdentity;
 import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -118,12 +119,18 @@ public class DefaultSyncHandler implemen
         config = DefaultSyncConfig.of(cfg);
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Nonnull
     @Override
     public String getName() {
         return config.getName();
     }
 
+    /**
+     * {@inheritDoc}
+     */
     @Nonnull
     @Override
     public SyncContext createContext(@Nonnull ExternalIdentityProvider idp, 
@Nonnull UserManager userManager, @Nonnull Root root)
@@ -131,6 +138,28 @@ public class DefaultSyncHandler implemen
         return new ContextImpl(idp, userManager, root);
     }
 
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public SyncedIdentity findIdentity(@Nonnull UserManager userManager, 
@Nonnull String id)
+            throws RepositoryException {
+        Authorizable auth = userManager.getAuthorizable(id);
+        if (auth == null) {
+            return null;
+        }
+        ExternalIdentityRef ref = getIdentityRef(auth);
+        Value[] lmValues = auth.getProperty(REP_LAST_SYNCED);
+        long lastModified = -1;
+        if (lmValues != null && lmValues.length > 0) {
+            lastModified = lmValues[0].getLong();
+        }
+        return new SyncedIdentityImpl(id, ref, auth.isGroup(), lastModified);
+    }
+
+    /**
+     * Internal implementation of the sync context
+     */
     private class ContextImpl implements SyncContext {
 
         private final ExternalIdentityProvider idp;
@@ -192,11 +221,73 @@ public class DefaultSyncHandler implemen
                     throw new IllegalArgumentException("identity must be user 
or group but was: " + identity);
                 }
                 if (log.isDebugEnabled()) {
-                    log.debug("sync({}) {}", identity.getId(), 
timer.getString());
+                    log.debug("sync({}) -> {} {}", new Object[]{
+                            identity.getExternalId().getString(), 
identity.getId(), timer.getString()
+                    });
+                }
+                return ret;
+            } catch (RepositoryException e) {
+                throw new SyncException(e);
+            }
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        @Override
+        public boolean sync(@Nonnull String id) throws SyncException {
+            try {
+                DebugTimer timer = new DebugTimer();
+                boolean ret = false;
+                // find authorizable
+                Authorizable auth = userManager.getAuthorizable(id);
+                if (auth == null) {
+                    return false;
+                }
+                // check if we need to deal with this authorizable
+                ExternalIdentityRef ref = getIdentityRef(auth);
+                if (ref == null || 
!idp.getName().equals(ref.getProviderName())) {
+                    return false;
+                }
+
+                if (auth instanceof Group) {
+                    Group group = (Group) auth;
+                    ExternalGroup external = idp.getGroup(id);
+                    timer.mark("retrieve");
+                    if (external == null) {
+                        if (group.getDeclaredMembers().hasNext()) {
+                            log.info("won't remove local group with members: 
{}", id);
+                        } else {
+                            auth.remove();
+                            log.debug("removing authorizable '{}' that no 
longer exists on IDP {}", id, idp.getName());
+                            timer.mark("remove");
+                            ret = true;
+                        }
+                    } else {
+                        ret = syncGroup(external, group);
+                        timer.mark("sync");
+                    }
+                } else {
+                    ExternalUser external = idp.getUser(id);
+                    timer.mark("retrieve");
+                    if (external == null) {
+                        auth.remove();
+                        log.debug("removing authorizable '{}' that no longer 
exists on IDP {}", id, idp.getName());
+                        timer.mark("remove");
+                        ret = true;
+                    } else {
+                        ret = syncUser(external, (User) auth);
+                        timer.mark("sync");
+                    }
+                }
+                if (log.isDebugEnabled()) {
+                    log.debug("sync({}) -> {} {}", new Object[]{id, 
ref.getString(), timer.getString()});
                 }
                 return ret;
             } catch (RepositoryException e) {
                 throw new SyncException(e);
+            } catch (ExternalIdentityException e) {
+                throw new SyncException(e);
             }
         }
 
@@ -346,7 +437,7 @@ public class DefaultSyncHandler implemen
                     declaredExternalGroups.put(grp.getID(), grp);
                 }
             }
-            timer.mark("existing");
+            timer.mark("reading");
 
             for (ExternalIdentityRef ref: externalGroups) {
                 log.debug("- processing membership {}", ref.getId());
@@ -564,20 +655,31 @@ public class DefaultSyncHandler implemen
          * @return {@code true} if same IDP.
          */
         private boolean isSameIDP(@Nullable Authorizable auth) throws 
RepositoryException {
-            if (auth == null) {
-                return false;
-            }
-            Value[] v = auth.getProperty(REP_EXTERNAL_ID);
-            if (v == null || v.length == 0) {
-                return false;
-            }
-            ExternalIdentityRef ref = 
ExternalIdentityRef.fromString(v[0].getString());
-            return idp.getName().equals(ref.getProviderName());
+            ExternalIdentityRef ref = getIdentityRef(auth);
+            return ref != null && idp.getName().equals(ref.getProviderName());
         }
 
     }
 
     /**
+     * Retrieves the external identity ref from the authorizable
+     * @param auth the authorizable
+     * @return the ref
+     * @throws RepositoryException if an error occurs
+     */
+    @CheckForNull
+    private static ExternalIdentityRef getIdentityRef(@Nullable Authorizable 
auth) throws RepositoryException {
+        if (auth == null) {
+            return null;
+        }
+        Value[] v = auth.getProperty(REP_EXTERNAL_ID);
+        if (v == null || v.length == 0) {
+            return null;
+        }
+        return ExternalIdentityRef.fromString(v[0].getString());
+    }
+
+    /**
      * Robust relative path concatenation.
      * @param paths relative paths
      * @return the concatenated path
@@ -604,4 +706,43 @@ public class DefaultSyncHandler implemen
         }
         return result.length() == 0 ? null : result.toString();
     }
+
+    private static class SyncedIdentityImpl implements SyncedIdentity {
+
+        private final String id;
+
+        private final ExternalIdentityRef ref;
+
+        private final boolean isGroup;
+
+        private final long lastSynced;
+
+        private SyncedIdentityImpl(String id, ExternalIdentityRef ref, boolean 
isGroup, long lastSynced) {
+            this.id = id;
+            this.ref = ref;
+            this.isGroup = isGroup;
+            this.lastSynced = lastSynced;
+        }
+
+        @Nonnull
+        @Override
+        public String getId() {
+            return id;
+        }
+
+        @Override
+        public ExternalIdentityRef getExternalIdRef() {
+            return ref;
+        }
+
+        @Override
+        public boolean isGroup() {
+            return false;
+        }
+
+        @Override
+        public long lastSynced() {
+            return lastSynced;
+        }
+    }
 }
\ No newline at end of file

Modified: 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java?rev=1576555&r1=1576554&r2=1576555&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModule.java
 Wed Mar 12 01:15:05 2014
@@ -21,7 +21,9 @@ import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
 
+import javax.annotation.Nonnull;
 import javax.jcr.Credentials;
+import javax.jcr.RepositoryException;
 import javax.jcr.SimpleCredentials;
 import javax.security.auth.Subject;
 import javax.security.auth.callback.CallbackHandler;
@@ -41,6 +43,7 @@ import org.apache.jackrabbit.oak.spi.sec
 import 
org.apache.jackrabbit.oak.spi.security.authentication.external.SyncException;
 import 
org.apache.jackrabbit.oak.spi.security.authentication.external.SyncHandler;
 import 
org.apache.jackrabbit.oak.spi.security.authentication.external.SyncManager;
+import 
org.apache.jackrabbit.oak.spi.security.authentication.external.SyncedIdentity;
 import org.apache.jackrabbit.oak.spi.whiteboard.Whiteboard;
 import org.apache.jackrabbit.oak.spi.whiteboard.WhiteboardUtils;
 import org.slf4j.Logger;
@@ -162,7 +165,28 @@ public class ExternalLoginModule extends
             return false;
         }
 
+        // remember userID as we need this so often
+        final String userId = credentials instanceof SimpleCredentials ? 
((SimpleCredentials) credentials).getUserID() : null;
         try {
+            SyncedIdentity sId = null;
+            if (userId != null) {
+                sId = syncHandler.findIdentity(getUserManager(), userId);
+                // if there exists an authorizable with the given userid but 
is not an external one or if it belongs to
+                // another IDP, we just ignore it.
+                if (sId != null) {
+                    if (sId.getExternalIdRef() == null) {
+                        log.debug("ignoring local user: {}", sId.getId());
+                        return false;
+                    }
+                    if 
(!sId.getExternalIdRef().getProviderName().equals(idp.getName())) {
+                        if (log.isDebugEnabled()) {
+                            log.debug("ignoring foreign identity: {} 
(idp={})", sId.getExternalIdRef().getString(), idp.getName());
+                        }
+                        return false;
+                    }
+                }
+            }
+
             externalUser = idp.authenticate(credentials);
             if (externalUser != null) {
                 log.debug("IDP {} returned valid user {}", idp.getName(), 
externalUser);
@@ -178,26 +202,38 @@ public class ExternalLoginModule extends
                 return true;
             } else {
                 if (log.isDebugEnabled()) {
-                    if (credentials instanceof SimpleCredentials) {
-                        log.debug("IDP {} returned null for simple creds of 
{}", idp.getName(), ((SimpleCredentials) credentials).getUserID());
+                    if (userId != null) {
+                        log.debug("IDP {} returned null for simple creds of 
{}", idp.getName(), userId);
                     } else {
                         log.debug("IDP {} returned null for {}", 
idp.getName(), credentials);
                     }
                 }
+
+                if (sId != null) {
+                    // invalidate the user if it exists as synced variant
+                    log.debug("local user exists for '{}'. re-validating.", 
sId.getId());
+                    validateUser(sId.getId());
+                }
+                return false;
             }
         } catch (ExternalIdentityException e) {
-            log.error("Error while authenticating credentials {} with {}", new 
Object[]{credentials, idp.getName(), e});
+            log.error("Error while authenticating '{}' with {}", new Object[]{
+                    userId == null ? credentials : userId, idp.getName(), e
+            });
             return false;
         } catch (LoginException e) {
-            log.debug("IDP {} throws login exception for {}", new Object[] 
{idp.getName(), credentials, e});
+            log.debug("IDP {} throws login exception for '{}': {}", new 
Object[] {
+                    idp.getName(), userId == null ? credentials : userId, 
e.getMessage()
+            });
             throw e;
-        } catch (SyncException e) {
-            log.debug("SyncHandler {} throws sync exception for {}", new 
Object[] {idp.getName(), credentials, e});
+        } catch (Exception e) {
+            log.debug("SyncHandler {} throws sync exception for '{}'", new 
Object[] {
+                    syncHandler.getName(), userId == null ? credentials : 
userId, e
+            });
             LoginException le = new LoginException("Error while syncing 
user.");
             le.initCause(e);
             throw le;
         }
-        return false;
     }
 
     @Override
@@ -231,7 +267,7 @@ public class ExternalLoginModule extends
      * @param user the external user
      * @throws SyncException if an error occurs
      */
-    private void syncUser(ExternalUser user) throws SyncException {
+    private void syncUser(@Nonnull ExternalUser user) throws SyncException {
         SyncContext context = null;
         try {
             Root root = getRoot();
@@ -242,9 +278,15 @@ public class ExternalLoginModule extends
             if (userManager == null) {
                 throw new SyncException("Cannot synchronize user. userManager 
== null");
             }
+            DebugTimer timer = new DebugTimer();
             context = syncHandler.createContext(idp, userManager, root);
             context.sync(user);
+            timer.mark("sync");
             root.commit();
+            timer.mark("commit");
+            if (log.isDebugEnabled()) {
+                log.debug("syncUser({}) {}", user.getId(), timer.getString());
+            }
         } catch (CommitFailedException e) {
             throw new SyncException("User synchronization failed during 
commit.", e);
         } finally {
@@ -254,6 +296,39 @@ public class ExternalLoginModule extends
         }
     }
 
+    /**
+     * Initiates synchronization of a possible remove user
+     * @param id the user id
+     */
+    private void validateUser(@Nonnull String id) throws SyncException {
+        SyncContext context = null;
+        try {
+            Root root = getRoot();
+            if (root == null) {
+                throw new SyncException("Cannot synchronize user. root == 
null");
+            }
+            UserManager userManager = getUserManager();
+            if (userManager == null) {
+                throw new SyncException("Cannot synchronize user. userManager 
== null");
+            }
+            DebugTimer timer = new DebugTimer();
+            context = syncHandler.createContext(idp, userManager, root);
+            context.sync(id);
+            timer.mark("sync");
+            root.commit();
+            timer.mark("commit");
+            if (log.isDebugEnabled()) {
+                log.debug("validateUser({}) {}", id, timer.getString());
+            }
+        } catch (CommitFailedException e) {
+            throw new SyncException("User synchronization failed during 
commit.", e);
+        } finally {
+            if (context != null) {
+                context.close();
+            }
+        }
+
+    }
     //------------------------------------------------< AbstractLoginModule 
>---
 
     @Override

Modified: 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java?rev=1576555&r1=1576554&r2=1576555&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-auth-external/src/main/java/org/apache/jackrabbit/oak/spi/security/authentication/external/impl/ExternalLoginModuleFactory.java
 Wed Mar 12 01:15:05 2014
@@ -42,7 +42,7 @@ import org.apache.jackrabbit.oak.spi.sec
 public class ExternalLoginModuleFactory implements LoginModuleFactory {
 
     @Property(
-            intValue = 150,
+            intValue = 50,
             label = "JAAS Ranking",
             description = "Specifying the ranking (i.e. sort order) of this 
login module entry. The entries are sorted " +
                     "in a descending order (i.e. higher value ranked 
configurations come first)."

Modified: 
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java?rev=1576555&r1=1576554&r2=1576555&view=diff
==============================================================================
--- 
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java
 (original)
+++ 
jackrabbit/oak/trunk/oak-auth-external/src/test/java/org/apache/jackrabbit/oak/spi/security/authentication/external/ExternalLoginModuleTest.java
 Wed Mar 12 01:15:05 2014
@@ -19,11 +19,14 @@ package org.apache.jackrabbit.oak.spi.se
 import java.util.HashMap;
 
 import javax.jcr.SimpleCredentials;
+import javax.jcr.Value;
 import javax.security.auth.login.LoginException;
 
 import org.apache.jackrabbit.api.security.user.Authorizable;
 import org.apache.jackrabbit.api.security.user.UserManager;
 import org.apache.jackrabbit.oak.api.ContentSession;
+import org.apache.jackrabbit.oak.namepath.NamePathMapper;
+import org.apache.jackrabbit.oak.plugins.value.ValueFactoryImpl;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Ignore;
@@ -144,6 +147,7 @@ public class ExternalLoginModuleTest ext
         UserManager userManager = getUserManager(root);
         ExternalUser externalUser = idp.getUser(userId);
         Authorizable user = userManager.createUser(externalUser.getId(), null);
+        user.setProperty("rep:externalId", new ValueFactoryImpl(root, 
NamePathMapper.DEFAULT).createValue(externalUser.getExternalId().getString()));
         root.commit();
 
         ContentSession cs = null;

Added: jackrabbit/oak/trunk/oak-auth-external/src/test/scripts/generate_ldif.pl
URL: 
http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-auth-external/src/test/scripts/generate_ldif.pl?rev=1576555&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-auth-external/src/test/scripts/generate_ldif.pl 
(added)
+++ jackrabbit/oak/trunk/oak-auth-external/src/test/scripts/generate_ldif.pl 
Wed Mar 12 01:15:05 2014
@@ -0,0 +1,199 @@
+#!/usr/bin/perl
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# script to generate a LDIF with 66 primary groups and 17,576 unique users.
+# There are additional 100 secondary groups, where indirectly all users are 
member of.
+# Each user is a member of about 6 or 7 groups.
+# The largest groups contain about 20% of the users (~3,500 users)
+# The users all have the same password "password"
+#
+# The oak-users.csv file contains all of the users. Here is an example of the 
data from this CSV:
+#
+# 3997,T0F9D,Told Xyla
+# 3998,U0F9E,Upshove Xerasia
+# 3999,V0F9F,Verve Xenicus
+# 4000,W0FA0,Wharf Xiphiid
+# 4001,X0FA1,Xyletic Xenial
+# 4002,Y0FA2,Yean Xylonic
+# 4003,Z0FA3,Zimocca Xylenol
+# 4004,A0FA4,Agnail Yukian
+# 4005,B0FA5,Boolian Yapman
+#
+# The columns are:
+# <sequential-number>,<user-id>,<users-full-name>
+#
+# Group membership for each user is based on the sequential number and the 
first letters of the first and last full-name.
+# The first letter of the names defined the user as being in groups 
"has_<letter>" for each part of the full name
+# Each user is part of groups:
+# <modulus>_of_five
+# <modulus>_of_seven
+# <modulus>_of_eleven
+# <modulus>_of_seventeen
+#
+# According to the user's <sequential-number> so that <modulus> = 
<sequential-number> % 5, 7, 11 and 17.
+# For example, uid=T0F9D (sequential-number=3997) is a member of groups 
two_of_five, zero_of_seven,
+# four_of_eleven and two_of_seventeen
+#
+# Alas, there is no seven_of_nine.
+#
+
+%allgroups = ();
+
+$base = "o=oak,dc=apache,dc=org";
+
+# 0,A0000,Adeem Anend
+# 1,B0001,Brenda Abashed
+
+@digits = ( "zero", "one", "two", "three", "four", "five", "six", "seven", 
"eight", "nine",
+            "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", 
"sixteen",
+            "seventeen", "eighteen", "nineteen"  );
+
+sub n_of_m {
+  local ( $num, $mod ) = @_;
+  local $n, $g;
+  $n = $num % $mod;
+  $g = @digits[$n] . "_of_" . @digits[$mod];
+  return $g;
+}
+
+sub do_group {
+  local ( $group ) = @_;
+
+  unless (defined($allgroups{$group})) {
+     $mod = <<"DONE";
+# define group $group
+dn: cn=$group,ou=Groups,$base
+changetype: add
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: $group
+uniquemember: cn=$name,ou=Users,$base
+
+DONE
+     print $mod;
+  } else {
+
+  $mod = <<"DONE";
+# modify group $group
+dn: cn=$group,ou=Groups,$base
+changetype: modify
+add: uniquemember
+uniquemember: cn=$name,ou=Users,$base
+
+DONE
+
+  print $mod;
+}
+  $allgroups{$group} .= $uid;
+}
+
+print <<"DONE";
+dn: ou=Groups,$base
+objectclass: top
+objectclass: organizationalUnit
+ou: groups
+
+dn: ou=Users,$base
+objectclass: top
+objectclass: organizationalUnit
+ou: Users
+
+dn: cn=admin,$base
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+objectclass: top
+uid: admin
+cn: Administrator
+displayName: Administrator
+givenName: Administrator
+sn: Administrator
+description: Administrator of test company
+mail: admin\@oak.example.org
+userPassword: password
+
+DONE
+
+while (<>) {
+  chomp;
+  $_ =~ s/\s+$//;
+
+  @fields = split /,/;
+
+  $num = @fields[0];
+  $id = lc @fields[1];
+  $name = @fields[2];
+  $name =~ /^([^ ]+)\s+([^ ]+)$/;
+  $fname = $1;
+  $lname = $2;
+
+
+$g = &n_of_m($num, 5);
+$g = $g.",".&n_of_m($num, 7);
+$g = $g.",".&n_of_m($num, 11);
+$g = $g.",".&n_of_m($num, 17);
+
+$fname =~/^(\w)/; $l1 = $1; $l1 =~ y/A-Z/a-z/;
+$lname =~/^(\w)/; $l2 = $1; $l2 =~ y/A-Z/a-z/;
+$g = $g.",has_$l1";
+$g = $g.",has_$l2" unless ($l1 eq $l2);
+
+#  print "num=$num id=$id name=$name fname=$fname lname=$lname groups=$g\n";
+
+  $ldif = <<"DONE";
+# $num,$id,$name
+# groups: $g
+#
+dn: cn=$name,ou=Users, $base
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+objectclass: top
+uid: $id
+cn: $name
+displayName: $name
+givenName: $fname
+sn: $lname
+description: $name is a test user with groups $g
+mail: $id\@oak.example.org
+userPassword: password
+
+DONE
+
+  print $ldif;
+
+  foreach $i (split /,/, $g) {
+     do_group($i);
+  }
+}
+
+foreach my $i (1..100) {
+print <<"DONE";
+
+dn: cn=dummy_$i,ou=Groups,$base
+changetype: add
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: dummy_$i
+DONE
+
+    foreach my $i ('a'..'z') {
+        print "uniquemember: cn=has_$i,ou=Groups,$base\n"
+    }
+}

Propchange: 
jackrabbit/oak/trunk/oak-auth-external/src/test/scripts/generate_ldif.pl
------------------------------------------------------------------------------
    svn:executable = *


Reply via email to