]> git.argeo.org Git - lgpl/argeo-commons.git/blobdiff - security/runtime/org.argeo.security.ldap/src/main/java/org/argeo/security/ldap/jcr/JcrLdapSynchronizer.java
Treat LDAP as slave only
[lgpl/argeo-commons.git] / security / runtime / org.argeo.security.ldap / src / main / java / org / argeo / security / ldap / jcr / JcrLdapSynchronizer.java
index 178785602d5aa7eff0ad8d5583c39210f0350fb0..08c985c3b750577f09fe404f2a6ad6a5b39afc28 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007-2012 Mathieu Baudier
+ * Copyright (C) 2007-2012 Argeo GmbH
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,7 +17,6 @@ package org.argeo.security.ldap.jcr;
 
 import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
@@ -27,31 +26,15 @@ import java.util.SortedSet;
 
 import javax.jcr.Node;
 import javax.jcr.NodeIterator;
-import javax.jcr.Property;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
-import javax.jcr.observation.Event;
-import javax.jcr.observation.EventIterator;
-import javax.jcr.observation.EventListener;
 import javax.jcr.query.Query;
 import javax.jcr.version.VersionManager;
-import javax.naming.Binding;
 import javax.naming.Name;
-import javax.naming.NamingException;
 import javax.naming.directory.BasicAttribute;
 import javax.naming.directory.DirContext;
 import javax.naming.directory.ModificationItem;
-import javax.naming.directory.SearchControls;
-import javax.naming.event.EventDirContext;
-import javax.naming.event.NamespaceChangeListener;
-import javax.naming.event.NamingEvent;
-import javax.naming.event.NamingExceptionEvent;
-import javax.naming.event.NamingListener;
-import javax.naming.event.ObjectChangeListener;
-import javax.naming.ldap.UnsolicitedNotification;
-import javax.naming.ldap.UnsolicitedNotificationEvent;
-import javax.naming.ldap.UnsolicitedNotificationListener;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -59,9 +42,10 @@ import org.argeo.ArgeoException;
 import org.argeo.jcr.ArgeoNames;
 import org.argeo.jcr.ArgeoTypes;
 import org.argeo.jcr.JcrUtils;
-import org.argeo.jcr.security.SecurityJcrUtils;
+import org.argeo.security.SecurityUtils;
+import org.argeo.security.jcr.JcrSecurityModel;
 import org.argeo.security.jcr.JcrUserDetails;
-import org.springframework.ldap.core.ContextExecutor;
+import org.argeo.security.jcr.SimpleJcrSecurityModel;
 import org.springframework.ldap.core.ContextMapper;
 import org.springframework.ldap.core.DirContextAdapter;
 import org.springframework.ldap.core.DirContextOperations;
@@ -73,7 +57,7 @@ import org.springframework.security.providers.encoding.PasswordEncoder;
 import org.springframework.security.userdetails.UserDetails;
 import org.springframework.security.userdetails.ldap.UserDetailsContextMapper;
 
-/** Guarantees that LDAP and JCR are in line. */
+/** Makes sure that LDAP and JCR are in line. */
 public class JcrLdapSynchronizer implements UserDetailsContextMapper,
                ArgeoNames {
        private final static Log log = LogFactory.getLog(JcrLdapSynchronizer.class);
@@ -86,28 +70,28 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
         * "http://forum.springsource.org/showthread.php?55955-Persistent-search-with-spring-ldap"
         * >this</a>
         */
-       private LdapTemplate rawLdapTemplate;
+       // private LdapTemplate rawLdapTemplate;
 
        private String userBase;
        private String usernameAttribute;
        private String passwordAttribute;
        private String[] userClasses;
+       // private String defaultUserRole ="ROLE_USER";
 
-       private NamingListener ldapUserListener;
-       private SearchControls subTreeSearchControls;
+       // private NamingListener ldapUserListener;
+       // private SearchControls subTreeSearchControls;
        private LdapUsernameToDnMapper usernameMapper;
 
        private PasswordEncoder passwordEncoder;
        private final Random random;
 
        // JCR
-       /** Admin session on the security workspace */
-       private Session securitySession;
+       /** Admin session on the main workspace */
+       private Session nodeSession;
        private Repository repository;
 
-       private String securityWorkspace = "security";
-
-       private JcrProfileListener jcrProfileListener;
+       // private JcrProfileListener jcrProfileListener;
+       private JcrSecurityModel jcrSecurityModel = new SimpleJcrSecurityModel();
 
        // Mapping
        private Map<String, String> propertyToAttributes = new HashMap<String, String>();
@@ -118,60 +102,70 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
 
        public void init() {
                try {
-                       securitySession = repository.login(securityWorkspace);
-
-                       synchronize();
-
-                       // LDAP
-                       subTreeSearchControls = new SearchControls();
-                       subTreeSearchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);
-                       // LDAP listener
-                       ldapUserListener = new LdapUserListener();
-                       rawLdapTemplate.executeReadOnly(new ContextExecutor() {
-                               public Object executeWithContext(DirContext ctx)
-                                               throws NamingException {
-                                       EventDirContext ectx = (EventDirContext) ctx.lookup("");
-                                       ectx.addNamingListener(userBase, "(" + usernameAttribute
-                                                       + "=*)", subTreeSearchControls, ldapUserListener);
-                                       return null;
-                               }
-                       });
+                       nodeSession = repository.login();
+
+                       // TODO put this in a different thread, and poll the LDAP server
+                       // until it is up
+                       try {
+                               synchronize();
+
+                               // LDAP
+                               // subTreeSearchControls = new SearchControls();
+                               // subTreeSearchControls
+                               // .setSearchScope(SearchControls.SUBTREE_SCOPE);
+                               // LDAP listener
+                               // ldapUserListener = new LdapUserListener();
+                               // rawLdapTemplate.executeReadOnly(new ContextExecutor() {
+                               // public Object executeWithContext(DirContext ctx)
+                               // throws NamingException {
+                               // EventDirContext ectx = (EventDirContext) ctx.lookup("");
+                               // ectx.addNamingListener(userBase, "("
+                               // + usernameAttribute + "=*)",
+                               // subTreeSearchControls, ldapUserListener);
+                               // return null;
+                               // }
+                               // });
+                       } catch (Exception e) {
+                               log.error("Could not synchronize and listen to LDAP,"
+                                               + " probably because the LDAP server is not available."
+                                               + " Restart the system as soon as possible.", e);
+                       }
 
                        // JCR
-                       String[] nodeTypes = { ArgeoTypes.ARGEO_USER_PROFILE };
-                       jcrProfileListener = new JcrProfileListener();
+                       // String[] nodeTypes = { ArgeoTypes.ARGEO_USER_PROFILE };
+                       // jcrProfileListener = new JcrProfileListener();
                        // noLocal is used so that we are not notified when we modify JCR
                        // from LDAP
-                       securitySession
-                                       .getWorkspace()
-                                       .getObservationManager()
-                                       .addEventListener(jcrProfileListener,
-                                                       Event.PROPERTY_CHANGED | Event.NODE_ADDED, "/",
-                                                       true, null, nodeTypes, true);
+                       // nodeSession
+                       // .getWorkspace()
+                       // .getObservationManager()
+                       // .addEventListener(jcrProfileListener,
+                       // Event.PROPERTY_CHANGED | Event.NODE_ADDED, "/",
+                       // true, null, nodeTypes, true);
                } catch (Exception e) {
-                       JcrUtils.logoutQuietly(securitySession);
+                       JcrUtils.logoutQuietly(nodeSession);
                        throw new ArgeoException("Cannot initialize LDAP/JCR synchronizer",
                                        e);
                }
        }
 
        public void destroy() {
-               JcrUtils.removeListenerQuietly(securitySession, jcrProfileListener);
-               JcrUtils.logoutQuietly(securitySession);
-               try {
-                       rawLdapTemplate.executeReadOnly(new ContextExecutor() {
-                               public Object executeWithContext(DirContext ctx)
-                                               throws NamingException {
-                                       EventDirContext ectx = (EventDirContext) ctx.lookup("");
-                                       ectx.removeNamingListener(ldapUserListener);
-                                       return null;
-                               }
-                       });
-               } catch (Exception e) {
-                       // silent (LDAP server may have been shutdown already)
-                       if (log.isTraceEnabled())
-                               log.trace("Cannot remove LDAP listener", e);
-               }
+               // JcrUtils.removeListenerQuietly(nodeSession, jcrProfileListener);
+               JcrUtils.logoutQuietly(nodeSession);
+               // try {
+               // rawLdapTemplate.executeReadOnly(new ContextExecutor() {
+               // public Object executeWithContext(DirContext ctx)
+               // throws NamingException {
+               // EventDirContext ectx = (EventDirContext) ctx.lookup("");
+               // ectx.removeNamingListener(ldapUserListener);
+               // return null;
+               // }
+               // });
+               // } catch (Exception e) {
+               // // silent (LDAP server may have been shutdown already)
+               // if (log.isTraceEnabled())
+               // log.trace("Cannot remove LDAP listener", e);
+               // }
        }
 
        /*
@@ -186,12 +180,20 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
                        List<String> userPaths = (List<String>) ldapTemplate.listBindings(
                                        userBaseName, new ContextMapper() {
                                                public Object mapFromContext(Object ctxObj) {
-                                                       return mapLdapToJcr((DirContextAdapter) ctxObj);
+                                                       try {
+                                                               return mapLdapToJcr((DirContextAdapter) ctxObj);
+                                                       } catch (Exception e) {
+                                                               // do not break process because of error
+                                                               log.error(
+                                                                               "Could not LDAP->JCR synchronize user "
+                                                                                               + ctxObj, e);
+                                                               return null;
+                                                       }
                                                }
                                        });
 
-                       // disable accounts which are not in LDAP
-                       Query query = securitySession
+                       // create accounts which are not in LDAP
+                       Query query = nodeSession
                                        .getWorkspace()
                                        .getQueryManager()
                                        .createQuery(
@@ -201,35 +203,74 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
                        while (it.hasNext()) {
                                Node userProfile = it.nextNode();
                                String path = userProfile.getPath();
-                               if (!userPaths.contains(path)) {
-                                       log.warn("Path "
-                                                       + path
-                                                       + " not found in LDAP, disabling user "
-                                                       + userProfile.getProperty(ArgeoNames.ARGEO_USER_ID)
-                                                                       .getString());
-                                       VersionManager versionManager = securitySession
-                                                       .getWorkspace().getVersionManager();
-                                       versionManager.checkout(userProfile.getPath());
-                                       userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, false);
-                                       securitySession.save();
-                                       versionManager.checkin(userProfile.getPath());
+                               try {
+                                       if (!userPaths.contains(path)) {
+                                               String username = userProfile
+                                                               .getProperty(ARGEO_USER_ID).getString();
+                                               // GrantedAuthority[] authorities = {new
+                                               // GrantedAuthorityImpl(defaultUserRole)};
+                                               GrantedAuthority[] authorities = {};
+                                               JcrUserDetails userDetails = new JcrUserDetails(
+                                                               userProfile, username, authorities);
+                                               String dn = createLdapUser(userDetails);
+                                               log.warn("Created ldap entry '" + dn + "' for user '"
+                                                               + username + "'");
+
+                                               // if(!userProfile.getProperty(ARGEO_ENABLED).getBoolean()){
+                                               // continue profiles;
+                                               // }
+                                               //
+                                               // log.warn("Path "
+                                               // + path
+                                               // + " not found in LDAP, disabling user "
+                                               // + userProfile.getProperty(ArgeoNames.ARGEO_USER_ID)
+                                               // .getString());
+
+                                               // Temporary hack to repair previous behaviour
+                                               if (!userProfile.getProperty(ARGEO_ENABLED)
+                                                               .getBoolean()) {
+                                                       VersionManager versionManager = nodeSession
+                                                                       .getWorkspace().getVersionManager();
+                                                       versionManager.checkout(userProfile.getPath());
+                                                       userProfile.setProperty(ArgeoNames.ARGEO_ENABLED,
+                                                                       true);
+                                                       nodeSession.save();
+                                                       versionManager.checkin(userProfile.getPath());
+                                               }
+                                       }
+                               } catch (Exception e) {
+                                       log.error("Cannot process " + path, e);
                                }
                        }
                } catch (Exception e) {
-                       JcrUtils.discardQuietly(securitySession);
-                       throw new ArgeoException("Cannot synchronized LDAP and JCR", e);
+                       JcrUtils.discardQuietly(nodeSession);
+                       log.error("Cannot synchronize LDAP and JCR", e);
+                       // throw new ArgeoException("Cannot synchronize LDAP and JCR", e);
                }
        }
 
+       private String createLdapUser(UserDetails user) {
+               DirContextAdapter ctx = new DirContextAdapter();
+               mapUserToContext(user, ctx);
+               DistinguishedName dn = usernameMapper.buildDn(user.getUsername());
+               ldapTemplate.bind(dn, ctx, null);
+               return dn.toString();
+       }
+
        /** Called during authentication in order to retrieve user details */
        public UserDetails mapUserFromContext(final DirContextOperations ctx,
                        final String username, GrantedAuthority[] authorities) {
-               log.debug("mapUserFromContext");
                if (ctx == null)
                        throw new ArgeoException("No LDAP information for user " + username);
-               Node userProfile = SecurityJcrUtils.createUserProfileIfNeeded(securitySession,
-                               username);
-               JcrUserDetails.checkAccountStatus(userProfile);
+
+               String ldapUsername = ctx.getStringAttribute(usernameAttribute);
+               if (!ldapUsername.equals(username))
+                       throw new ArgeoException("Logged in with username " + username
+                                       + " but LDAP user is " + ldapUsername);
+
+               Node userProfile = jcrSecurityModel.sync(nodeSession, username,
+                               SecurityUtils.authoritiesToStringList(authorities));
+               // JcrUserDetails.checkAccountStatus(userProfile);
 
                // password
                SortedSet<?> passwordAttributes = ctx
@@ -258,50 +299,16 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
         * @return path to user profile
         */
        protected synchronized String mapLdapToJcr(DirContextAdapter ctx) {
-               Session session = securitySession;
+               Session session = nodeSession;
                try {
                        // process
                        String username = ctx.getStringAttribute(usernameAttribute);
-                       Node userHome = SecurityJcrUtils.createUserHomeIfNeeded(session, username);
-                       Node userProfile; // = userHome.getNode(ARGEO_PROFILE);
-                       if (userHome.hasNode(ARGEO_PROFILE)) {
-                               userProfile = userHome.getNode(ARGEO_PROFILE);
-
-                               // compatibility with legacy, will be removed
-                               if (!userProfile.hasProperty(ARGEO_ENABLED)) {
-                                       session.getWorkspace().getVersionManager()
-                                                       .checkout(userProfile.getPath());
-                                       userProfile.setProperty(ARGEO_ENABLED, true);
-                                       userProfile.setProperty(ARGEO_ACCOUNT_NON_EXPIRED, true);
-                                       userProfile.setProperty(ARGEO_ACCOUNT_NON_LOCKED, true);
-                                       userProfile
-                                                       .setProperty(ARGEO_CREDENTIALS_NON_EXPIRED, true);
-                                       session.save();
-                                       session.getWorkspace().getVersionManager()
-                                                       .checkin(userProfile.getPath());
-                               }
-                       } else {
-                               userProfile = SecurityJcrUtils.createUserProfile(securitySession,
-                                               username);
-                               userProfile.getSession().save();
-                               userProfile.getSession().getWorkspace().getVersionManager()
-                                               .checkin(userProfile.getPath());
-                       }
 
+                       Node userProfile = jcrSecurityModel.sync(session, username, null);
                        Map<String, String> modifications = new HashMap<String, String>();
                        for (String jcrProperty : propertyToAttributes.keySet())
                                ldapToJcr(userProfile, jcrProperty, ctx, modifications);
 
-                       // assign default values
-                       // if (!userProfile.hasProperty(Property.JCR_DESCRIPTION)
-                       // && !modifications.containsKey(Property.JCR_DESCRIPTION))
-                       // modifications.put(Property.JCR_DESCRIPTION, "");
-                       // if (!userProfile.hasProperty(Property.JCR_TITLE))
-                       // modifications.put(Property.JCR_TITLE,
-                       // userProfile.getProperty(ARGEO_FIRST_NAME).getString()
-                       // + " "
-                       // + userProfile.getProperty(ARGEO_LAST_NAME)
-                       // .getString());
                        int modifCount = modifications.size();
                        if (modifCount > 0) {
                                session.getWorkspace().getVersionManager()
@@ -338,11 +345,6 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
                                                                + jcrProperty);
 
                        String value = ctx.getStringAttribute(ldapAttribute);
-                       // if (value == null && Property.JCR_TITLE.equals(jcrProperty))
-                       // value = "";
-                       // if (value == null &&
-                       // Property.JCR_DESCRIPTION.equals(jcrProperty))
-                       // value = "";
                        String jcrValue = userProfile.hasProperty(jcrProperty) ? userProfile
                                        .getProperty(jcrProperty).getString() : null;
                        if (value != null && jcrValue != null) {
@@ -375,8 +377,9 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
 
                final JcrUserDetails jcrUserDetails = (JcrUserDetails) user;
                try {
-                       Node userProfile = securitySession.getNode(
-                                       jcrUserDetails.getHomePath()).getNode(ARGEO_PROFILE);
+                       Node userProfile = nodeSession
+                                       .getNode(jcrUserDetails.getHomePath()).getNode(
+                                                       ARGEO_PROFILE);
                        for (String jcrProperty : propertyToAttributes.keySet()) {
                                if (userProfile.hasProperty(jcrProperty)) {
                                        ModificationItem mi = jcrToLdap(jcrProperty, userProfile
@@ -450,17 +453,13 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
        }
 
        public void setRawLdapTemplate(LdapTemplate rawLdapTemplate) {
-               this.rawLdapTemplate = rawLdapTemplate;
+               // this.rawLdapTemplate = rawLdapTemplate;
        }
 
        public void setRepository(Repository repository) {
                this.repository = repository;
        }
 
-       public void setSecurityWorkspace(String securityWorkspace) {
-               this.securityWorkspace = securityWorkspace;
-       }
-
        public void setUserBase(String userBase) {
                this.userBase = userBase;
        }
@@ -489,125 +488,130 @@ public class JcrLdapSynchronizer implements UserDetailsContextMapper,
                this.passwordEncoder = passwordEncoder;
        }
 
-       /** Listen to LDAP */
-       class LdapUserListener implements ObjectChangeListener,
-                       NamespaceChangeListener, UnsolicitedNotificationListener {
-
-               public void namingExceptionThrown(NamingExceptionEvent evt) {
-                       evt.getException().printStackTrace();
-               }
-
-               public void objectChanged(NamingEvent evt) {
-                       Binding user = evt.getNewBinding();
-                       // TODO find a way not to be called when JCR is the source of the
-                       // modification
-                       DirContextAdapter ctx = (DirContextAdapter) ldapTemplate
-                                       .lookup(user.getName());
-                       mapLdapToJcr(ctx);
-               }
-
-               public void objectAdded(NamingEvent evt) {
-                       Binding user = evt.getNewBinding();
-                       DirContextAdapter ctx = (DirContextAdapter) ldapTemplate
-                                       .lookup(user.getName());
-                       mapLdapToJcr(ctx);
-               }
-
-               public void objectRemoved(NamingEvent evt) {
-                       if (log.isDebugEnabled())
-                               log.debug(evt);
-               }
-
-               public void objectRenamed(NamingEvent evt) {
-                       if (log.isDebugEnabled())
-                               log.debug(evt);
-               }
-
-               public void notificationReceived(UnsolicitedNotificationEvent evt) {
-                       UnsolicitedNotification notification = evt.getNotification();
-                       NamingException ne = notification.getException();
-                       String msg = "LDAP notification " + "ID=" + notification.getID()
-                                       + ", referrals=" + notification.getReferrals();
-                       if (ne != null) {
-                               if (log.isTraceEnabled())
-                                       log.trace(msg + ", exception= " + ne, ne);
-                               else
-                                       log.warn(msg + ", exception= " + ne);
-                       } else if (log.isDebugEnabled()) {
-                               log.debug("Unsollicited LDAP notification " + msg);
-                       }
-               }
-
+       public void setJcrSecurityModel(JcrSecurityModel jcrSecurityModel) {
+               this.jcrSecurityModel = jcrSecurityModel;
        }
 
-       /** Listen to JCR */
-       class JcrProfileListener implements EventListener {
-
-               public void onEvent(EventIterator events) {
-                       try {
-                               final Map<Name, List<ModificationItem>> modifications = new HashMap<Name, List<ModificationItem>>();
-                               while (events.hasNext()) {
-                                       Event event = events.nextEvent();
-                                       try {
-                                               if (Event.PROPERTY_CHANGED == event.getType()) {
-                                                       Property property = (Property) securitySession
-                                                                       .getItem(event.getPath());
-                                                       String propertyName = property.getName();
-                                                       Node userProfile = property.getParent();
-                                                       String username = userProfile.getProperty(
-                                                                       ARGEO_USER_ID).getString();
-                                                       if (propertyToAttributes.containsKey(propertyName)) {
-                                                               Name name = usernameMapper.buildDn(username);
-                                                               if (!modifications.containsKey(name))
-                                                                       modifications.put(name,
-                                                                                       new ArrayList<ModificationItem>());
-                                                               String value = property.getString();
-                                                               ModificationItem mi = jcrToLdap(propertyName,
-                                                                               value);
-                                                               if (mi != null)
-                                                                       modifications.get(name).add(mi);
-                                                       }
-                                               } else if (Event.NODE_ADDED == event.getType()) {
-                                                       Node userProfile = securitySession.getNode(event
-                                                                       .getPath());
-                                                       String username = userProfile.getProperty(
-                                                                       ARGEO_USER_ID).getString();
-                                                       Name name = usernameMapper.buildDn(username);
-                                                       for (String propertyName : propertyToAttributes
-                                                                       .keySet()) {
-                                                               if (!modifications.containsKey(name))
-                                                                       modifications.put(name,
-                                                                                       new ArrayList<ModificationItem>());
-                                                               String value = userProfile.getProperty(
-                                                                               propertyName).getString();
-                                                               ModificationItem mi = jcrToLdap(propertyName,
-                                                                               value);
-                                                               if (mi != null)
-                                                                       modifications.get(name).add(mi);
-                                                       }
-                                               }
-                                       } catch (RepositoryException e) {
-                                               throw new ArgeoException("Cannot process event "
-                                                               + event, e);
-                                       }
-                               }
-
-                               for (Name name : modifications.keySet()) {
-                                       List<ModificationItem> userModifs = modifications.get(name);
-                                       int modifCount = userModifs.size();
-                                       ldapTemplate.modifyAttributes(name, userModifs
-                                                       .toArray(new ModificationItem[modifCount]));
-                                       if (log.isDebugEnabled())
-                                               log.debug("Mapped " + modifCount + " JCR modification"
-                                                               + (modifCount == 1 ? "" : "s") + " to " + name);
-                               }
-                       } catch (Exception e) {
-                               // if (log.isDebugEnabled())
-                               // e.printStackTrace();
-                               throw new ArgeoException("Cannot process JCR events ("
-                                               + e.getMessage() + ")", e);
-                       }
-               }
+       /** Listen to LDAP */
+       // class LdapUserListener implements ObjectChangeListener,
+       // NamespaceChangeListener, UnsolicitedNotificationListener {
+       //
+       // public void namingExceptionThrown(NamingExceptionEvent evt) {
+       // evt.getException().printStackTrace();
+       // }
+       //
+       // public void objectChanged(NamingEvent evt) {
+       // Binding user = evt.getNewBinding();
+       // // TODO find a way not to be called when JCR is the source of the
+       // // modification
+       // DirContextAdapter ctx = (DirContextAdapter) ldapTemplate
+       // .lookup(user.getName());
+       // mapLdapToJcr(ctx);
+       // }
+       //
+       // public void objectAdded(NamingEvent evt) {
+       // Binding user = evt.getNewBinding();
+       // DirContextAdapter ctx = (DirContextAdapter) ldapTemplate
+       // .lookup(user.getName());
+       // mapLdapToJcr(ctx);
+       // }
+       //
+       // public void objectRemoved(NamingEvent evt) {
+       // if (log.isDebugEnabled())
+       // log.debug(evt);
+       // }
+       //
+       // public void objectRenamed(NamingEvent evt) {
+       // if (log.isDebugEnabled())
+       // log.debug(evt);
+       // }
+       //
+       // public void notificationReceived(UnsolicitedNotificationEvent evt) {
+       // UnsolicitedNotification notification = evt.getNotification();
+       // NamingException ne = notification.getException();
+       // String msg = "LDAP notification " + "ID=" + notification.getID()
+       // + ", referrals=" + notification.getReferrals();
+       // if (ne != null) {
+       // if (log.isTraceEnabled())
+       // log.trace(msg + ", exception= " + ne, ne);
+       // else
+       // log.warn(msg + ", exception= " + ne);
+       // } else if (log.isDebugEnabled()) {
+       // log.debug("Unsollicited LDAP notification " + msg);
+       // }
+       // }
+       //
+       // }
 
-       }
+       /** Listen to JCR */
+       // class JcrProfileListener implements EventListener {
+       //
+       // public void onEvent(EventIterator events) {
+       // try {
+       // final Map<Name, List<ModificationItem>> modifications = new HashMap<Name,
+       // List<ModificationItem>>();
+       // while (events.hasNext()) {
+       // Event event = events.nextEvent();
+       // try {
+       // if (Event.PROPERTY_CHANGED == event.getType()) {
+       // Property property = (Property) nodeSession
+       // .getItem(event.getPath());
+       // String propertyName = property.getName();
+       // Node userProfile = property.getParent();
+       // String username = userProfile.getProperty(
+       // ARGEO_USER_ID).getString();
+       // if (propertyToAttributes.containsKey(propertyName)) {
+       // Name name = usernameMapper.buildDn(username);
+       // if (!modifications.containsKey(name))
+       // modifications.put(name,
+       // new ArrayList<ModificationItem>());
+       // String value = property.getString();
+       // ModificationItem mi = jcrToLdap(propertyName,
+       // value);
+       // if (mi != null)
+       // modifications.get(name).add(mi);
+       // }
+       // } else if (Event.NODE_ADDED == event.getType()) {
+       // Node userProfile = nodeSession.getNode(event
+       // .getPath());
+       // String username = userProfile.getProperty(
+       // ARGEO_USER_ID).getString();
+       // Name name = usernameMapper.buildDn(username);
+       // for (String propertyName : propertyToAttributes
+       // .keySet()) {
+       // if (!modifications.containsKey(name))
+       // modifications.put(name,
+       // new ArrayList<ModificationItem>());
+       // String value = userProfile.getProperty(
+       // propertyName).getString();
+       // ModificationItem mi = jcrToLdap(propertyName,
+       // value);
+       // if (mi != null)
+       // modifications.get(name).add(mi);
+       // }
+       // }
+       // } catch (RepositoryException e) {
+       // throw new ArgeoException("Cannot process event "
+       // + event, e);
+       // }
+       // }
+       //
+       // for (Name name : modifications.keySet()) {
+       // List<ModificationItem> userModifs = modifications.get(name);
+       // int modifCount = userModifs.size();
+       // ldapTemplate.modifyAttributes(name, userModifs
+       // .toArray(new ModificationItem[modifCount]));
+       // if (log.isDebugEnabled())
+       // log.debug("Mapped " + modifCount + " JCR modification"
+       // + (modifCount == 1 ? "" : "s") + " to " + name);
+       // }
+       // } catch (Exception e) {
+       // // if (log.isDebugEnabled())
+       // // e.printStackTrace();
+       // throw new ArgeoException("Cannot process JCR events ("
+       // + e.getMessage() + ")", e);
+       // }
+       // }
+       //
+       // }
 }