]> git.argeo.org Git - lgpl/argeo-commons.git/blobdiff - org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java
Make CMS production ready
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / kernel / NodeUserAdmin.java
index 75cd44491cb20278714a5b96f138cda04978385d..3cc3dbfb39c4e95684e74fb64a78a77717cdd514 100644 (file)
@@ -1,5 +1,8 @@
 package org.argeo.cms.internal.kernel;
 
+import static org.argeo.cms.internal.kernel.KernelUtils.getFrameworkProp;
+import static org.argeo.cms.internal.kernel.KernelUtils.getOsgiInstanceDir;
+
 import java.io.File;
 import java.io.IOException;
 import java.net.URI;
@@ -13,11 +16,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import javax.jcr.Node;
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.Value;
-import javax.jcr.security.Privilege;
+import javax.jcr.Repository;
 import javax.naming.InvalidNameException;
 import javax.naming.ldap.LdapName;
 import javax.transaction.TransactionManager;
@@ -25,159 +24,136 @@ import javax.transaction.TransactionManager;
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
-import org.argeo.ArgeoException;
 import org.argeo.cms.CmsException;
 import org.argeo.cms.auth.AuthConstants;
-import org.argeo.jcr.ArgeoJcrConstants;
-import org.argeo.jcr.ArgeoNames;
-import org.argeo.jcr.ArgeoTypes;
-import org.argeo.jcr.JcrUtils;
-import org.argeo.jcr.UserJcrUtils;
+import org.argeo.node.NodeConstants;
 import org.argeo.osgi.useradmin.LdapUserAdmin;
 import org.argeo.osgi.useradmin.LdifUserAdmin;
 import org.argeo.osgi.useradmin.UserAdminConf;
 import org.argeo.osgi.useradmin.UserDirectory;
 import org.argeo.osgi.useradmin.UserDirectoryException;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
 import org.osgi.service.useradmin.Authorization;
 import org.osgi.service.useradmin.Role;
 import org.osgi.service.useradmin.User;
 import org.osgi.service.useradmin.UserAdmin;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+import bitronix.tm.resource.ehcache.EhCacheXAResourceProducer;
 
-public class NodeUserAdmin implements UserAdmin {
+/**
+ * Aggregates multiple {@link UserDirectory} and integrates them with this node
+ * system roles.
+ */
+public class NodeUserAdmin implements UserAdmin, KernelConstants {
        private final static Log log = LogFactory.getLog(NodeUserAdmin.class);
        final static LdapName ROLES_BASE;
        static {
                try {
                        ROLES_BASE = new LdapName(AuthConstants.ROLES_BASEDN);
                } catch (InvalidNameException e) {
-                       throw new UserDirectoryException("Cannot initialize "
-                                       + NodeUserAdmin.class, e);
+                       throw new UserDirectoryException("Cannot initialize " + NodeUserAdmin.class, e);
                }
        }
 
+       private final BundleContext bc = FrameworkUtil.getBundle(getClass()).getBundleContext();
+
+       // DAOs
        private UserAdmin nodeRoles = null;
        private Map<LdapName, UserAdmin> userAdmins = new HashMap<LdapName, UserAdmin>();
 
-       /** The home base path. */
-       private String homeBasePath = "/home";
-       private String peopleBasePath = ArgeoJcrConstants.PEOPLE_BASE_PATH;
-       private Session adminSession;
+       // JCR
+       // private String homeBasePath = "/home";
+       // private String peopleBasePath = ArgeoJcrConstants.PEOPLE_BASE_PATH;
+       // private Repository repository;
+       // private Session adminSession;
 
-       public NodeUserAdmin(Session adminSession) {
-               this.adminSession = adminSession;
-               File osgiInstanceDir = KernelUtils.getOsgiInstanceDir();
-               File nodeBaseDir = new File(osgiInstanceDir, "node");
+       private final String cacheName = UserDirectory.class.getName();
+
+       public NodeUserAdmin() {
+               // DAOs
+               File nodeBaseDir = new File(getOsgiInstanceDir(), DIR_NODE);
                nodeBaseDir.mkdirs();
+               String userAdminUri = getFrameworkProp(NodeConstants.USERADMIN_URIS);
+               initUserAdmins(userAdminUri, nodeBaseDir);
+               String nodeRolesUri = getFrameworkProp(NodeConstants.ROLES_URI);
+               initNodeRoles(nodeRolesUri, nodeBaseDir);
 
-               String userAdminUri = KernelUtils
-                               .getFrameworkProp(KernelConstants.USERADMIN_URIS);
-               if (userAdminUri == null) {
-                       String demoBaseDn = "dc=example,dc=com";
-                       File businessRolesFile = new File(nodeBaseDir, demoBaseDn + ".ldif");
-                       if (!businessRolesFile.exists())
-                               try {
-                                       FileUtils.copyInputStreamToFile(getClass()
-                                                       .getResourceAsStream(demoBaseDn + ".ldif"),
-                                                       businessRolesFile);
-                               } catch (IOException e) {
-                                       throw new CmsException("Cannot copy demo resource", e);
-                               }
-                       userAdminUri = businessRolesFile.toURI().toString();
-               }
+               new ServiceTracker<>(bc, TransactionManager.class, new TransactionManagerStc()).open();
+       }
 
-               String[] uris = userAdminUri.split(" ");
-               for (String uri : uris) {
-                       URI u;
-                       try {
-                               u = new URI(uri);
-                               if (u.getPath() == null)
-                                       throw new CmsException("URI " + uri
-                                                       + " must have a path in order to determine base DN");
-                               if (u.getScheme() == null) {
-                                       if (uri.startsWith("/") || uri.startsWith("./")
-                                                       || uri.startsWith("../"))
-                                               u = new File(uri).getCanonicalFile().toURI();
-                                       else if (!uri.contains("/"))
-                                               u = new File(nodeBaseDir, uri).getCanonicalFile()
-                                                               .toURI();
-                                       else
-                                               throw new CmsException("Cannot interpret " + uri
-                                                               + " as an uri");
-                               } else if (u.getScheme().equals("file")) {
-                                       u = new File(u).getCanonicalFile().toURI();
-                               }
-                       } catch (Exception e) {
-                               throw new CmsException(
-                                               "Cannot interpret " + uri + " as an uri", e);
-                       }
-                       Dictionary<String, ?> properties = UserAdminConf.uriAsProperties(u
-                                       .toString());
-                       UserDirectory businessRoles;
-                       if (u.getScheme().startsWith("ldap")) {
-                               businessRoles = new LdapUserAdmin(properties);
-                       } else {
-                               businessRoles = new LdifUserAdmin(properties);
+       private class TransactionManagerStc implements ServiceTrackerCustomizer<TransactionManager, TransactionManager> {
+
+               @Override
+               public TransactionManager addingService(ServiceReference<TransactionManager> reference) {
+                       TransactionManager transactionManager = bc.getService(reference);
+                       ((UserDirectory) nodeRoles).setTransactionManager(transactionManager);
+                       for (UserAdmin userAdmin : userAdmins.values()) {
+                               if (userAdmin instanceof UserDirectory)
+                                       ((UserDirectory) userAdmin).setTransactionManager(transactionManager);
                        }
-                       businessRoles.init();
-                       addUserAdmin(businessRoles.getBaseDn(), (UserAdmin) businessRoles);
                        if (log.isDebugEnabled())
-                               log.debug("User directory " + businessRoles.getBaseDn() + " ["
-                                               + u.getScheme() + "] enabled.");
+                               log.debug("Set transaction manager");
+                       return transactionManager;
                }
 
-               // Node roles
-               String nodeRolesUri = KernelUtils
-                               .getFrameworkProp(KernelConstants.ROLES_URI);
-               String baseNodeRoleDn = AuthConstants.ROLES_BASEDN;
-               if (nodeRolesUri == null) {
-                       File nodeRolesFile = new File(nodeBaseDir, baseNodeRoleDn + ".ldif");
-                       if (!nodeRolesFile.exists())
-                               try {
-                                       FileUtils.copyInputStreamToFile(getClass()
-                                                       .getResourceAsStream("demo.ldif"), nodeRolesFile);
-                               } catch (IOException e) {
-                                       throw new CmsException("Cannot copy demo resource", e);
-                               }
-                       nodeRolesUri = nodeRolesFile.toURI().toString();
+               @Override
+               public void modifiedService(ServiceReference<TransactionManager> reference, TransactionManager service) {
                }
 
-               Dictionary<String, ?> nodeRolesProperties = UserAdminConf
-                               .uriAsProperties(nodeRolesUri);
-               if (!nodeRolesProperties.get(UserAdminConf.baseDn.property()).equals(
-                               baseNodeRoleDn)) {
-                       throw new CmsException("Invalid base dn for node roles");
-                       // TODO deal with "mounted" roles with a different baseDN
+               @Override
+               public void removedService(ServiceReference<TransactionManager> reference, TransactionManager service) {
+                       ((UserDirectory) nodeRoles).setTransactionManager(null);
+                       for (UserAdmin userAdmin : userAdmins.values()) {
+                               if (userAdmin instanceof UserDirectory)
+                                       ((UserDirectory) userAdmin).setTransactionManager(null);
+                       }
                }
-               UserDirectory nodeRoles;
-               if (nodeRolesUri.startsWith("ldap")) {
-                       nodeRoles = new LdapUserAdmin(nodeRolesProperties);
-               } else {
-                       nodeRoles = new LdifUserAdmin(nodeRolesProperties);
+
+       }
+
+       @Deprecated
+       public NodeUserAdmin(TransactionManager transactionManager, Repository repository) {
+               // this.repository = repository;
+               // try {
+               // this.adminSession = this.repository.login();
+               // } catch (RepositoryException e) {
+               // throw new CmsException("Cannot log-in", e);
+               // }
+
+               // DAOs
+               File nodeBaseDir = new File(getOsgiInstanceDir(), DIR_NODE);
+               nodeBaseDir.mkdirs();
+               String userAdminUri = getFrameworkProp(NodeConstants.USERADMIN_URIS);
+               initUserAdmins(userAdminUri, nodeBaseDir);
+               String nodeRolesUri = getFrameworkProp(NodeConstants.ROLES_URI);
+               initNodeRoles(nodeRolesUri, nodeBaseDir);
+
+               // Transaction manager
+               ((UserDirectory) nodeRoles).setTransactionManager(transactionManager);
+               for (UserAdmin userAdmin : userAdmins.values()) {
+                       if (userAdmin instanceof UserDirectory)
+                               ((UserDirectory) userAdmin).setTransactionManager(transactionManager);
                }
-               nodeRoles.setExternalRoles(this);
-               nodeRoles.init();
-               addUserAdmin(baseNodeRoleDn, (UserAdmin) nodeRoles);
-               if (log.isTraceEnabled())
-                       log.trace("Node roles enabled.");
 
                // JCR
-               initJcr(adminSession);
+               // initJcr(adminSession);
        }
 
-       Dictionary<String, ?> currentState() {
+       Dictionary<String, Object> currentState() {
                Dictionary<String, Object> res = new Hashtable<String, Object>();
                for (LdapName name : userAdmins.keySet()) {
                        StringBuilder buf = new StringBuilder();
                        if (userAdmins.get(name) instanceof UserDirectory) {
-                               UserDirectory userDirectory = (UserDirectory) userAdmins
-                                               .get(name);
-                               String uri = UserAdminConf.propertiesAsUri(
-                                               userDirectory.getProperties()).toString();
+                               UserDirectory userDirectory = (UserDirectory) userAdmins.get(name);
+                               String uri = UserAdminConf.propertiesAsUri(userDirectory.getProperties()).toString();
                                res.put(uri, "");
                        } else {
-                               buf.append('/').append(name.toString())
-                                               .append("?readOnly=true");
+                               buf.append('/').append(name.toString()).append("?readOnly=true");
                        }
                }
                return res;
@@ -186,9 +162,15 @@ public class NodeUserAdmin implements UserAdmin {
        public void destroy() {
                for (LdapName name : userAdmins.keySet()) {
                        if (userAdmins.get(name) instanceof UserDirectory) {
-                               UserDirectory userDirectory = (UserDirectory) userAdmins
-                                               .get(name);
+                               UserDirectory userDirectory = (UserDirectory) userAdmins.get(name);
+                               try {
+                                       // FIXME Make it less bitronix dependant
+                                       EhCacheXAResourceProducer.unregisterXAResource(cacheName, userDirectory.getXaResource());
+                               } catch (Exception e) {
+                                       log.error("Cannot unregister resource from Bitronix", e);
+                               }
                                userDirectory.destroy();
+
                        }
                }
        }
@@ -242,51 +224,34 @@ public class NodeUserAdmin implements UserAdmin {
                // gather system roles
                Set<String> systemRoles = new HashSet<String>();
                for (String role : rawAuthorization.getRoles()) {
-                       Authorization auth = nodeRoles.getAuthorization((User) userAdmin
-                                       .getRole(role));
+                       Authorization auth = nodeRoles.getAuthorization((User) userAdmin.getRole(role));
                        systemRoles.addAll(Arrays.asList(auth.getRoles()));
                }
-               Authorization authorization = new NodeAuthorization(
-                               rawAuthorization.getName(), rawAuthorization.toString(),
+               Authorization authorization = new NodeAuthorization(rawAuthorization.getName(), rawAuthorization.toString(),
                                systemRoles, rawAuthorization.getRoles());
-               syncJcr(adminSession, authorization);
+               // syncJcr(adminSession, authorization);
                return authorization;
        }
 
        //
        // USER ADMIN AGGREGATOR
        //
-       public synchronized void addUserAdmin(String baseDn, UserAdmin userAdmin) {
-               if (baseDn.equals(AuthConstants.ROLES_BASEDN)) {
-                       nodeRoles = userAdmin;
-                       return;
-               }
-
+       public void addUserAdmin(String baseDn, UserAdmin userAdmin) {
                if (userAdmins.containsKey(baseDn))
-                       throw new UserDirectoryException(
-                                       "There is already a user admin for " + baseDn);
+                       throw new UserDirectoryException("There is already a user admin for " + baseDn);
                try {
                        userAdmins.put(new LdapName(baseDn), userAdmin);
                } catch (InvalidNameException e) {
-                       throw new UserDirectoryException("Badly formatted base DN "
-                                       + baseDn, e);
+                       throw new UserDirectoryException("Badly formatted base DN " + baseDn, e);
                }
-       }
-
-       public synchronized void removeUserAdmin(String baseDn) {
-               if (baseDn.equals(AuthConstants.ROLES_BASEDN))
-                       throw new UserDirectoryException("Node roles cannot be removed.");
-               LdapName base;
-               try {
-                       base = new LdapName(baseDn);
-               } catch (InvalidNameException e) {
-                       throw new UserDirectoryException("Badly formatted base DN "
-                                       + baseDn, e);
+               if (userAdmin instanceof UserDirectory) {
+                       try {
+                               // FIXME Make it less bitronix dependant
+                               EhCacheXAResourceProducer.registerXAResource(cacheName, ((UserDirectory) userAdmin).getXaResource());
+                       } catch (Exception e) {
+                               log.error("Cannot register resource to Bitronix", e);
+                       }
                }
-               if (!userAdmins.containsKey(base))
-                       throw new UserDirectoryException("There is no user admin for "
-                                       + base);
-               userAdmins.remove(base);
        }
 
        private UserAdmin findUserAdmin(String name) {
@@ -306,161 +271,241 @@ public class NodeUserAdmin implements UserAdmin {
                                res.add(userAdmins.get(baseDn));
                }
                if (res.size() == 0)
-                       throw new UserDirectoryException("Cannot find user admin for "
-                                       + name);
+                       throw new UserDirectoryException("Cannot find user admin for " + name);
                if (res.size() > 1)
-                       throw new UserDirectoryException("Multiple user admin found for "
-                                       + name);
+                       throw new UserDirectoryException("Multiple user admin found for " + name);
                return res.get(0);
        }
 
        public void setTransactionManager(TransactionManager transactionManager) {
                if (nodeRoles instanceof UserDirectory)
-                       ((UserDirectory) nodeRoles)
-                                       .setTransactionManager(transactionManager);
+                       ((UserDirectory) nodeRoles).setTransactionManager(transactionManager);
                for (UserAdmin userAdmin : userAdmins.values()) {
                        if (userAdmin instanceof UserDirectory)
-                               ((UserDirectory) userAdmin)
-                                               .setTransactionManager(transactionManager);
+                               ((UserDirectory) userAdmin).setTransactionManager(transactionManager);
                }
        }
 
-       /*
-        * JCR
-        */
-       private void initJcr(Session adminSession) {
-               try {
-                       JcrUtils.mkdirs(adminSession, homeBasePath);
-                       JcrUtils.mkdirs(adminSession, peopleBasePath);
-                       adminSession.save();
-
-                       JcrUtils.addPrivilege(adminSession, homeBasePath,
-                                       AuthConstants.ROLE_USER_ADMIN, Privilege.JCR_READ);
-                       JcrUtils.addPrivilege(adminSession, peopleBasePath,
-                                       AuthConstants.ROLE_USER_ADMIN, Privilege.JCR_ALL);
-                       adminSession.save();
-               } catch (RepositoryException e) {
-                       throw new CmsException("Cannot initialize node user admin", e);
+       private void initUserAdmins(String userAdminUri, File nodeBaseDir) {
+               if (userAdminUri == null) {
+                       String demoBaseDn = "dc=example,dc=com";
+                       File businessRolesFile = new File(nodeBaseDir, demoBaseDn + ".ldif");
+                       if (!businessRolesFile.exists())
+                               try {
+                                       FileUtils.copyInputStreamToFile(getClass().getResourceAsStream(demoBaseDn + ".ldif"),
+                                                       businessRolesFile);
+                               } catch (IOException e) {
+                                       throw new CmsException("Cannot copy demo resource", e);
+                               }
+                       userAdminUri = businessRolesFile.toURI().toString();
                }
-       }
-
-       private Node syncJcr(Session session, Authorization authorization) {
-               // TODO check user name validity (e.g. should not start by ROLE_)
-               String username = authorization.getName();
-               String[] roles = authorization.getRoles();
-               try {
-                       Node userHome = UserJcrUtils.getUserHome(session, username);
-                       if (userHome == null) {
-                               String homePath = generateUserPath(homeBasePath, username);
-                               if (session.itemExists(homePath))// duplicate user id
-                                       userHome = session.getNode(homePath).getParent()
-                                                       .addNode(JcrUtils.lastPathElement(homePath));
-                               else
-                                       userHome = JcrUtils.mkdirs(session, homePath);
-                               // userHome = JcrUtils.mkfolders(session, homePath);
-                               userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
-                               userHome.setProperty(ArgeoNames.ARGEO_USER_ID, username);
-                               session.save();
-
-                               JcrUtils.clearAccessControList(session, homePath, username);
-                               JcrUtils.addPrivilege(session, homePath, username,
-                                               Privilege.JCR_ALL);
+               String[] uris = userAdminUri.split(" ");
+               for (String uri : uris) {
+                       URI u;
+                       try {
+                               u = new URI(uri);
+                               if (u.getPath() == null)
+                                       throw new CmsException("URI " + uri + " must have a path in order to determine base DN");
+                               if (u.getScheme() == null) {
+                                       if (uri.startsWith("/") || uri.startsWith("./") || uri.startsWith("../"))
+                                               u = new File(uri).getCanonicalFile().toURI();
+                                       else if (!uri.contains("/")) {
+                                               u = new URI(nodeBaseDir.toURI() + uri);
+                                               // u = new File(nodeBaseDir, uri).getCanonicalFile()
+                                               // .toURI();
+                                       } else
+                                               throw new CmsException("Cannot interpret " + uri + " as an uri");
+                               } else if (u.getScheme().equals("file")) {
+                                       u = new File(u).getCanonicalFile().toURI();
+                               }
+                       } catch (Exception e) {
+                               throw new CmsException("Cannot interpret " + uri + " as an uri", e);
                        }
-
-                       Node userProfile = UserJcrUtils.getUserProfile(session, username);
-                       // new user
-                       if (userProfile == null) {
-                               String personPath = generateUserPath(peopleBasePath, username);
-                               Node personBase;
-                               if (session.itemExists(personPath))// duplicate user id
-                                       personBase = session.getNode(personPath).getParent()
-                                                       .addNode(JcrUtils.lastPathElement(personPath));
-                               else
-                                       personBase = JcrUtils.mkdirs(session, personPath);
-                               userProfile = personBase.addNode(ArgeoNames.ARGEO_PROFILE);
-                               userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE);
-                               userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username);
-                               userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, true);
-                               userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED,
-                                               true);
-                               userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED,
-                                               true);
-                               userProfile.setProperty(
-                                               ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED, true);
-                               session.save();
-
-                               JcrUtils.clearAccessControList(session, userProfile.getPath(),
-                                               username);
-                               JcrUtils.addPrivilege(session, userProfile.getPath(), username,
-                                               Privilege.JCR_READ);
+                       Dictionary<String, ?> properties = UserAdminConf.uriAsProperties(u.toString());
+                       UserDirectory businessRoles;
+                       if (u.getScheme().startsWith("ldap")) {
+                               businessRoles = new LdapUserAdmin(properties);
+                       } else {
+                               businessRoles = new LdifUserAdmin(properties);
                        }
-
-                       // Remote roles
-                       if (roles != null) {
-                               writeRemoteRoles(userProfile, roles);
+                       businessRoles.init();
+                       String baseDn = businessRoles.getBaseDn();
+                       if (userAdmins.containsKey(baseDn))
+                               throw new UserDirectoryException("There is already a user admin for " + baseDn);
+                       try {
+                               userAdmins.put(new LdapName(baseDn), (UserAdmin) businessRoles);
+                       } catch (InvalidNameException e) {
+                               throw new UserDirectoryException("Badly formatted base DN " + baseDn, e);
                        }
-                       adminSession.save();
-                       return userProfile;
-               } catch (RepositoryException e) {
-                       JcrUtils.discardQuietly(session);
-                       throw new ArgeoException("Cannot sync node security model for "
-                                       + username, e);
+                       addUserAdmin(businessRoles.getBaseDn(), (UserAdmin) businessRoles);
+                       if (log.isDebugEnabled())
+                               log.debug("User directory " + businessRoles.getBaseDn() + " [" + u.getScheme() + "] enabled.");
                }
+
        }
 
-       /** Generate path for a new user home */
-       private String generateUserPath(String base, String username) {
-               LdapName dn;
-               try {
-                       dn = new LdapName(username);
-               } catch (InvalidNameException e) {
-                       throw new ArgeoException("Invalid name " + username, e);
-               }
-               String userId = dn.getRdn(dn.size() - 1).getValue().toString();
-               int atIndex = userId.indexOf('@');
-               if (atIndex > 0) {
-                       String domain = userId.substring(0, atIndex);
-                       String name = userId.substring(atIndex + 1);
-                       return base + '/' + JcrUtils.firstCharsToPath(domain, 2) + '/'
-                                       + domain + '/' + JcrUtils.firstCharsToPath(name, 2) + '/'
-                                       + name;
-               } else if (atIndex == 0 || atIndex == (userId.length() - 1)) {
-                       throw new ArgeoException("Unsupported username " + userId);
-               } else {
-                       return base + '/' + JcrUtils.firstCharsToPath(userId, 2) + '/'
-                                       + userId;
+       private void initNodeRoles(String nodeRolesUri, File nodeBaseDir) {
+               String baseNodeRoleDn = AuthConstants.ROLES_BASEDN;
+               if (nodeRolesUri == null) {
+                       File nodeRolesFile = new File(nodeBaseDir, baseNodeRoleDn + ".ldif");
+                       if (!nodeRolesFile.exists())
+                               try {
+                                       FileUtils.copyInputStreamToFile(getClass().getResourceAsStream(baseNodeRoleDn + ".ldif"),
+                                                       nodeRolesFile);
+                               } catch (IOException e) {
+                                       throw new CmsException("Cannot copy demo resource", e);
+                               }
+                       nodeRolesUri = nodeRolesFile.toURI().toString();
                }
-       }
 
-       /** Write remote roles used by remote access in the home directory */
-       private void writeRemoteRoles(Node userHome, String[] roles)
-                       throws RepositoryException {
-               boolean writeRoles = false;
-               if (userHome.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) {
-                       Value[] remoteRoles = userHome.getProperty(
-                                       ArgeoNames.ARGEO_REMOTE_ROLES).getValues();
-                       if (remoteRoles.length != roles.length)
-                               writeRoles = true;
-                       else
-                               for (int i = 0; i < remoteRoles.length; i++)
-                                       if (!remoteRoles[i].getString().equals(roles[i]))
-                                               writeRoles = true;
-               } else
-                       writeRoles = true;
-
-               if (writeRoles) {
-                       userHome.getSession().getWorkspace().getVersionManager()
-                                       .checkout(userHome.getPath());
-                       userHome.setProperty(ArgeoNames.ARGEO_REMOTE_ROLES, roles);
-                       JcrUtils.updateLastModified(userHome);
-                       userHome.getSession().save();
-                       userHome.getSession().getWorkspace().getVersionManager()
-                                       .checkin(userHome.getPath());
-                       if (log.isDebugEnabled())
-                               log.debug("Wrote remote roles " + roles + " for "
-                                               + userHome.getProperty(ArgeoNames.ARGEO_USER_ID));
+               Dictionary<String, ?> nodeRolesProperties = UserAdminConf.uriAsProperties(nodeRolesUri);
+               if (!nodeRolesProperties.get(UserAdminConf.baseDn.property()).equals(baseNodeRoleDn)) {
+                       throw new CmsException("Invalid base dn for node roles");
+                       // TODO deal with "mounted" roles with a different baseDN
+               }
+               if (nodeRolesUri.startsWith("ldap")) {
+                       nodeRoles = new LdapUserAdmin(nodeRolesProperties);
+               } else {
+                       nodeRoles = new LdifUserAdmin(nodeRolesProperties);
                }
+               ((UserDirectory) nodeRoles).setExternalRoles(this);
+               ((UserDirectory) nodeRoles).init();
+               addUserAdmin(baseNodeRoleDn, (UserAdmin) nodeRoles);
+               if (log.isTraceEnabled())
+                       log.trace("Node roles enabled.");
 
        }
 
+       /*
+        * JCR
+        */
+       // private void initJcr(Session adminSession) {
+       // try {
+       // JcrUtils.mkdirs(adminSession, homeBasePath);
+       // JcrUtils.mkdirs(adminSession, peopleBasePath);
+       // adminSession.save();
+       //
+       // JcrUtils.addPrivilege(adminSession, homeBasePath,
+       // AuthConstants.ROLE_USER_ADMIN, Privilege.JCR_READ);
+       // JcrUtils.addPrivilege(adminSession, peopleBasePath,
+       // AuthConstants.ROLE_USER_ADMIN, Privilege.JCR_ALL);
+       // adminSession.save();
+       // } catch (RepositoryException e) {
+       // throw new CmsException("Cannot initialize node user admin", e);
+       // }
+       // }
+       //
+       // private Node syncJcr(Session session, Authorization authorization) {
+       // // TODO check user name validity (e.g. should not start by ROLE_)
+       // String username = authorization.getName();
+       // // String[] roles = authorization.getRoles();
+       // try {
+       // Node userHome = UserJcrUtils.getUserHome(session, username);
+       // if (userHome == null) {
+       // String homePath = generateUserPath(homeBasePath, username);
+       // if (session.itemExists(homePath))// duplicate user id
+       // userHome =
+       // session.getNode(homePath).getParent().addNode(JcrUtils.lastPathElement(homePath));
+       // else
+       // userHome = JcrUtils.mkdirs(session, homePath);
+       // // userHome = JcrUtils.mkfolders(session, homePath);
+       // userHome.addMixin(ArgeoTypes.ARGEO_USER_HOME);
+       // userHome.setProperty(ArgeoNames.ARGEO_USER_ID, username);
+       // session.save();
+       //
+       // JcrUtils.clearAccessControList(session, homePath, username);
+       // JcrUtils.addPrivilege(session, homePath, username, Privilege.JCR_ALL);
+       // }
+       //
+       // Node userProfile = UserJcrUtils.getUserProfile(session, username);
+       // // new user
+       // if (userProfile == null) {
+       // String personPath = generateUserPath(peopleBasePath, username);
+       // Node personBase;
+       // if (session.itemExists(personPath))// duplicate user id
+       // personBase =
+       // session.getNode(personPath).getParent().addNode(JcrUtils.lastPathElement(personPath));
+       // else
+       // personBase = JcrUtils.mkdirs(session, personPath);
+       // userProfile = personBase.addNode(ArgeoNames.ARGEO_PROFILE);
+       // userProfile.addMixin(ArgeoTypes.ARGEO_USER_PROFILE);
+       // userProfile.setProperty(ArgeoNames.ARGEO_USER_ID, username);
+       // userProfile.setProperty(ArgeoNames.ARGEO_ENABLED, true);
+       // userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_EXPIRED, true);
+       // userProfile.setProperty(ArgeoNames.ARGEO_ACCOUNT_NON_LOCKED, true);
+       // userProfile.setProperty(ArgeoNames.ARGEO_CREDENTIALS_NON_EXPIRED, true);
+       // session.save();
+       //
+       // JcrUtils.clearAccessControList(session, userProfile.getPath(), username);
+       // JcrUtils.addPrivilege(session, userProfile.getPath(), username,
+       // Privilege.JCR_READ);
+       // }
+       //
+       // // Remote roles
+       // // if (roles != null) {
+       // // writeRemoteRoles(userProfile, roles);
+       // // }
+       // if (adminSession.hasPendingChanges())
+       // adminSession.save();
+       // return userProfile;
+       // } catch (RepositoryException e) {
+       // JcrUtils.discardQuietly(session);
+       // throw new ArgeoException("Cannot sync node security model for " +
+       // username, e);
+       // }
+       // }
+       //
+       // /** Generate path for a new user home */
+       // private String generateUserPath(String base, String username) {
+       // LdapName dn;
+       // try {
+       // dn = new LdapName(username);
+       // } catch (InvalidNameException e) {
+       // throw new ArgeoException("Invalid name " + username, e);
+       // }
+       // String userId = dn.getRdn(dn.size() - 1).getValue().toString();
+       // int atIndex = userId.indexOf('@');
+       // if (atIndex > 0) {
+       // String domain = userId.substring(0, atIndex);
+       // String name = userId.substring(atIndex + 1);
+       // return base + '/' + JcrUtils.firstCharsToPath(domain, 2) + '/' + domain +
+       // '/'
+       // + JcrUtils.firstCharsToPath(name, 2) + '/' + name;
+       // } else if (atIndex == 0 || atIndex == (userId.length() - 1)) {
+       // throw new ArgeoException("Unsupported username " + userId);
+       // } else {
+       // return base + '/' + JcrUtils.firstCharsToPath(userId, 2) + '/' + userId;
+       // }
+       // }
+
+       // /** Write remote roles used by remote access in the home directory */
+       // private void writeRemoteRoles(Node userHome, String[] roles)
+       // throws RepositoryException {
+       // boolean writeRoles = false;
+       // if (userHome.hasProperty(ArgeoNames.ARGEO_REMOTE_ROLES)) {
+       // Value[] remoteRoles = userHome.getProperty(
+       // ArgeoNames.ARGEO_REMOTE_ROLES).getValues();
+       // if (remoteRoles.length != roles.length)
+       // writeRoles = true;
+       // else
+       // for (int i = 0; i < remoteRoles.length; i++)
+       // if (!remoteRoles[i].getString().equals(roles[i]))
+       // writeRoles = true;
+       // } else
+       // writeRoles = true;
+       //
+       // if (writeRoles) {
+       // userHome.getSession().getWorkspace().getVersionManager()
+       // .checkout(userHome.getPath());
+       // userHome.setProperty(ArgeoNames.ARGEO_REMOTE_ROLES, roles);
+       // JcrUtils.updateLastModified(userHome);
+       // userHome.getSession().save();
+       // userHome.getSession().getWorkspace().getVersionManager()
+       // .checkin(userHome.getPath());
+       // if (log.isDebugEnabled())
+       // log.debug("Wrote remote roles " + roles + " for "
+       // + userHome.getProperty(ArgeoNames.ARGEO_USER_ID));
+       // }
+       //
+       // }
 }