Use deploy config for node user admin
authorMathieu Baudier <mbaudier@argeo.org>
Tue, 6 Sep 2016 10:40:54 +0000 (10:40 +0000)
committerMathieu Baudier <mbaudier@argeo.org>
Tue, 6 Sep 2016 10:40:54 +0000 (10:40 +0000)
git-svn-id: https://svn.argeo.org/commons/trunk@9091 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc

org.argeo.cms.api/src/org/argeo/node/NodeConstants.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/FirstInitProperties.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java
org.argeo.cms/src/org/argeo/cms/internal/kernel/UserDirectoryServiceFactory.java [new file with mode: 0644]
org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminConf.java

index 039b2f9e9dd2ee6edc2ed570707bf751f2635b84..477b0b96b7ed92abbbc83944c9a41dd42ed3fb21 100644 (file)
@@ -8,20 +8,19 @@ public interface NodeConstants {
        String NODE_DEPLOYMENT_PID = "org.argeo.node.deployment";
        String NODE_INSTANCE_PID = "org.argeo.node.instance";
 
-       String NODE_REPO_PID = "org.argeo.node.repo";
+//     String NODE_REPO_PID = "org.argeo.node.repo";
        String NODE_USER_ADMIN_PID = "org.argeo.node.userAdmin";
 
        /*
         * FACTORY PIDs
         */
        String NODE_REPOS_FACTORY_PID = "org.argeo.node.repos";
+       String NODE_USER_DIRECTORIES_FACTORY_PID = "org.argeo.node.userDirectories";
 
        /*
         * DEPLOY
         */
        String DEPLOY_BASEDN = "ou=deploy,ou=node";
-//     String DEPLOY_SERVICES_BASEDN = "ou=services," + DEPLOY_BASEDN;
-//     String DEPLOY_SERVICE_FACTORIES_BASEDN = "ou=serviceFactories," + DEPLOY_BASEDN;
 
        /*
         * FRAMEWORK PROPERTIES
@@ -43,4 +42,9 @@ public interface NodeConstants {
        String CN = "cn";
        String OU = "ou";
        String LABELED_URI = "labeledUri";
+       
+       /*
+        * STANDARD VALUES
+        */
+       String DEFAULT = "default";
 }
index 45e218a15701e9e3b00c1ae8619350566389f68c..a2d072e5bcc62923d945d681ccef1c7b4b9a5c95 100644 (file)
@@ -118,6 +118,7 @@ public class CmsDeployment implements NodeDeployment {
 
                prepareDataModel(KernelUtils.openAdminSession(deployedNodeRepository));
                Hashtable<String, String> regProps = new Hashtable<String, String>();
+               regProps.put(NodeConstants.CN, ArgeoJcrConstants.ALIAS_HOME);
                regProps.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS, ArgeoJcrConstants.ALIAS_HOME);
                homeRepository = new HomeRepository(deployedNodeRepository);
                // register
index 23d2f266d89325c71dc99bc168498340049b37ab..87fae05cf2af4333c97078af43c6b3c48c6a3a6c 100644 (file)
@@ -100,16 +100,22 @@ public class CmsState implements NodeState {
                bc.registerService(RepositoryFactory.class, repositoryFactory, null);
 
                // Security
+//             UserDirectoryServiceFactory userDirectoryServiceFactory = new UserDirectoryServiceFactory();
+//             shutdownHooks.add(() -> userDirectoryServiceFactory.shutdown());
+//             bc.registerService(ManagedServiceFactory.class, userDirectoryServiceFactory,
+//                             LangUtils.init(Constants.SERVICE_PID, NodeConstants.NODE_USER_DIRECTORIES_FACTORY_PID));
+
                NodeUserAdmin userAdmin = new NodeUserAdmin();
                shutdownHooks.add(() -> userAdmin.destroy());
                Dictionary<String, Object> props = userAdmin.currentState();
                props.put(Constants.SERVICE_PID, NodeConstants.NODE_USER_ADMIN_PID);
-               bc.registerService(UserAdmin.class, userAdmin, props);
+               bc.registerService(ManagedServiceFactory.class, userAdmin, props);
 
                // UI
                bc.registerService(ApplicationConfiguration.class, new MaintenanceUi(),
                                LangUtils.init(KernelConstants.CONTEXT_NAME_PROP, "system"));
-               bc.registerService(ApplicationConfiguration.class, new UserUi(), LangUtils.init(KernelConstants.CONTEXT_NAME_PROP, "user"));
+               bc.registerService(ApplicationConfiguration.class, new UserUi(),
+                               LangUtils.init(KernelConstants.CONTEXT_NAME_PROP, "user"));
        }
 
        private void initTransactionManager() {
index 572631effec0487231da9dd0c4c6c114f06c60f5..fbe206644d169aa57003e93dfd0608e9fbad1b16 100644 (file)
@@ -6,6 +6,7 @@ import java.io.Writer;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.Dictionary;
+import java.util.List;
 import java.util.SortedMap;
 import java.util.TreeMap;
 
@@ -20,6 +21,7 @@ import org.apache.commons.logging.LogFactory;
 import org.argeo.cms.CmsException;
 import org.argeo.jcr.ArgeoJcrConstants;
 import org.argeo.node.NodeConstants;
+import org.argeo.osgi.useradmin.UserAdminConf;
 import org.argeo.util.naming.AttributesDictionary;
 import org.argeo.util.naming.LdifParser;
 import org.argeo.util.naming.LdifWriter;
@@ -64,13 +66,25 @@ class DeployConfig implements ConfigurationListener {
                        deployConfigs = new LdifParser().read(in);
                }
 
+               // node repository
                Dictionary<String, Object> nodeConfig = firstInit
                                .getNodeRepositoryConfig(getProps(NodeConstants.NODE_REPOS_FACTORY_PID, ArgeoJcrConstants.ALIAS_NODE));
                // node repository is mandatory
                putFactoryDeployConfig(NodeConstants.NODE_REPOS_FACTORY_PID, nodeConfig);
 
+               // user admin
+
+               List<Dictionary<String, Object>> userDirectoryConfigs = firstInit.getUserDirectoryConfigs();
+               for (int i = 0; i < userDirectoryConfigs.size(); i++) {
+                       Dictionary<String, Object> userDirectoryConfig = userDirectoryConfigs.get(i);
+                       String cn = Integer.toString(i);
+                       userDirectoryConfig.put(NodeConstants.CN, cn);
+                       putFactoryDeployConfig(NodeConstants.NODE_USER_ADMIN_PID, userDirectoryConfig);
+               }
+
+               // http server
                Dictionary<String, Object> webServerConfig = firstInit
-                               .getHttpServerConfig(getProps(KernelConstants.JETTY_FACTORY_PID, ArgeoJcrConstants.ALIAS_NODE));
+                               .getHttpServerConfig(getProps(KernelConstants.JETTY_FACTORY_PID, NodeConstants.DEFAULT));
                if (!webServerConfig.isEmpty())
                        putFactoryDeployConfig(KernelConstants.JETTY_FACTORY_PID, webServerConfig);
 
index 6b34c207ccfc12482178a024b0b6985ca2920793..2a054d5be1af1c10c63c1216ddd39b4e0fe792dd 100644 (file)
@@ -5,16 +5,21 @@ import static org.argeo.cms.internal.kernel.KernelUtils.getFrameworkProp;
 import java.io.File;
 import java.io.FileFilter;
 import java.io.IOException;
+import java.net.URI;
+import java.util.ArrayList;
 import java.util.Dictionary;
 import java.util.Hashtable;
+import java.util.List;
 
 import org.apache.commons.io.FileUtils;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.argeo.cms.CmsException;
+import org.argeo.cms.auth.AuthConstants;
 import org.argeo.jcr.ArgeoJcrConstants;
 import org.argeo.node.NodeConstants;
 import org.argeo.node.RepoConf;
+import org.argeo.osgi.useradmin.UserAdminConf;
 import org.eclipse.equinox.http.jetty.JettyConstants;
 
 /**
@@ -41,6 +46,7 @@ class FirstInitProperties {
                return props;
        }
 
+       /** Override the provided config with the framework properties */
        Dictionary<String, Object> getHttpServerConfig(Dictionary<String, Object> provided) {
                String httpPort = getFrameworkProp("org.osgi.service.http.port");
                String httpsPort = getFrameworkProp("org.osgi.service.http.port.secure");
@@ -66,11 +72,77 @@ class FirstInitProperties {
                        if (httpHost != null) {
                                props.put(JettyConstants.HTTP_HOST, httpHost);
                        }
-                       props.put(NodeConstants.CN, "default");
+                       props.put(NodeConstants.CN, NodeConstants.DEFAULT);
                }
                return props;
        }
 
+       List<Dictionary<String, Object>> getUserDirectoryConfigs() {
+               List<Dictionary<String, Object>> res = new ArrayList<>();
+               File nodeBaseDir = KernelUtils.getOsgiInstancePath(KernelConstants.DIR_NODE).toFile();
+               List<String> uris = new ArrayList<>();
+
+               // node roles
+               String nodeRolesUri = getFrameworkProp(NodeConstants.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(baseNodeRoleDn + ".ldif"),
+                                                       nodeRolesFile);
+                               } catch (IOException e) {
+                                       throw new CmsException("Cannot copy demo resource", e);
+                               }
+                       nodeRolesUri = nodeRolesFile.toURI().toString();
+               }
+               uris.add(nodeRolesUri);
+
+               // Business roles
+               String userAdminUris = getFrameworkProp(NodeConstants.USERADMIN_URIS);
+               if (userAdminUris == 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);
+                               }
+                       userAdminUris = businessRolesFile.toURI().toString();
+               }
+               for (String userAdminUri : userAdminUris.split(" "))
+                       uris.add(userAdminUri);
+
+               // Interprets URIs
+               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 = KernelUtils.getOsgiInstanceUri(KernelConstants.DIR_NODE + '/' + uri);
+                                               // u = new URI(nodeBaseDir.toURI() + uri);
+                                       } 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, Object> properties = UserAdminConf.uriAsProperties(u.toString());
+                       res.add(properties);
+               }
+
+               return res;
+       }
+
        /**
         * Called before node initialisation, in order populate OSGi instance are
         * with some files (typically LDIF, etc).
index 3de2c7934ac43f221aca27d1cdc5ed8ddf44f281..4f58e7525cb620d6549a6926e020f0501bd87870 100644 (file)
@@ -42,6 +42,7 @@ import org.argeo.cms.auth.CurrentUser;
 import org.argeo.node.ArgeoLogListener;
 import org.argeo.node.ArgeoLogger;
 import org.argeo.node.NodeConstants;
+import org.argeo.osgi.useradmin.UserAdminConf;
 import org.osgi.framework.Constants;
 import org.osgi.framework.ServiceReference;
 import org.osgi.service.cm.ConfigurationAdmin;
@@ -161,11 +162,11 @@ class NodeLogger implements ArgeoLogger, LogListener {
                        Object factoryPid = sr.getProperty(ConfigurationAdmin.SERVICE_FACTORYPID);
                        if (factoryPid != null)
                                sb.append(" " + ConfigurationAdmin.SERVICE_FACTORYPID + ": " + factoryPid);
-                       else {
-                               Object servicePid = sr.getProperty(Constants.SERVICE_PID);
-                               if (servicePid != null)
-                                       sb.append(" " + Constants.SERVICE_PID + ": " + servicePid);
-                       }
+//                     else {
+//                             Object servicePid = sr.getProperty(Constants.SERVICE_PID);
+//                             if (servicePid != null)
+//                                     sb.append(" " + Constants.SERVICE_PID + ": " + servicePid);
+//                     }
                        // servlets
                        Object whiteBoardPattern = sr.getProperty(KernelConstants.WHITEBOARD_PATTERN_PROP);
                        if (whiteBoardPattern != null)
@@ -175,6 +176,11 @@ class NodeLogger implements ArgeoLogger, LogListener {
                        Object contextName = sr.getProperty(KernelConstants.CONTEXT_NAME_PROP);
                        if (contextName != null)
                                sb.append(" " + KernelConstants.CONTEXT_NAME_PROP + ": " + contextName);
+                       
+                       // user directories
+                       Object baseDn = sr.getProperty(UserAdminConf.baseDn.name());
+                       if (baseDn != null)
+                               sb.append(" " + UserAdminConf.baseDn.name() + ": " + baseDn);
                }
                return sb.toString();
        }
index fd9ba31dfbe76ba6cd0e502fc42b042fadbfaa23..c04d820da418d1fd0cf6c8fa4fae813f1e1b1548 100644 (file)
@@ -1,11 +1,7 @@
 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;
+import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Dictionary;
@@ -16,12 +12,10 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import javax.jcr.Repository;
 import javax.naming.InvalidNameException;
 import javax.naming.ldap.LdapName;
 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.cms.CmsException;
@@ -33,17 +27,18 @@ 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.Constants;
 import org.osgi.framework.FrameworkUtil;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.cm.ConfigurationException;
-import org.osgi.service.cm.ManagedService;
+import org.osgi.service.cm.ManagedServiceFactory;
 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;
 
@@ -51,7 +46,7 @@ import bitronix.tm.resource.ehcache.EhCacheXAResourceProducer;
  * Aggregates multiple {@link UserDirectory} and integrates them with this node
  * system roles.
  */
-class NodeUserAdmin implements UserAdmin, ManagedService, KernelConstants {
+class NodeUserAdmin implements UserAdmin, ManagedServiceFactory, KernelConstants {
        private final static Log log = LogFactory.getLog(NodeUserAdmin.class);
        final static LdapName ROLES_BASE;
        static {
@@ -67,6 +62,11 @@ class NodeUserAdmin implements UserAdmin, ManagedService, KernelConstants {
        // DAOs
        private UserAdmin nodeRoles = null;
        private Map<LdapName, UserAdmin> userAdmins = new HashMap<LdapName, UserAdmin>();
+       private Map<String, LdapName> pidToBaseDn = new HashMap<>();
+
+       private ServiceRegistration<UserAdmin> userAdminReg;
+
+       private final ServiceTracker<TransactionManager, TransactionManager> tmTracker;
 
        // JCR
        // private String homeBasePath = "/home";
@@ -78,26 +78,89 @@ class NodeUserAdmin implements UserAdmin, ManagedService, KernelConstants {
 
        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);
-
-               new ServiceTracker<>(bc, TransactionManager.class, new TransactionManagerStc()).open();
+               // 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);
+
+               // new ServiceTracker<>(bc, TransactionManager.class, new
+               // TransactionManagerStc()).open();
+               tmTracker = new TransactionManagerStc();
+               tmTracker.open();
        }
 
        @Override
-       public void updated(Dictionary<String, ?> properties) throws ConfigurationException {
+       public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException {
+               String uri = (String) properties.get(UserAdminConf.uri.name());
+               URI u;
+               try {
+                       u = new URI(uri);
+               } catch (URISyntaxException e) {
+                       throw new CmsException("Badly formatted URI " + uri, e);
+               }
+               UserDirectory userDirectory = u.getScheme().equals("ldap") ? new LdapUserAdmin(properties)
+                               : new LdifUserAdmin(properties);
+               LdapName baseDn;
+               try {
+                       baseDn = new LdapName(userDirectory.getBaseDn());
+               } catch (InvalidNameException e) {
+                       throw new CmsException("Badly formatted base DN " + userDirectory.getBaseDn(), e);
+               }
+               if (isRolesDnBase(baseDn)) {
+                       nodeRoles = (UserAdmin) userDirectory;
+                       userDirectory.setExternalRoles(this);
+               }
+               userDirectory.init();
+               addUserAdmin(baseDn.toString(), (UserAdmin) userDirectory);
+
+               // publish user directory
+               Dictionary<String, Object> regProps = new Hashtable<>();
+               regProps.put(Constants.SERVICE_PID, pid);
+               regProps.put(UserAdminConf.baseDn.name(), baseDn);
+               bc.registerService(UserDirectory.class, userDirectory, regProps);
+               pidToBaseDn.put(pid, baseDn);
+
+               if (log.isDebugEnabled()) {
+                       log.debug("User directory " + userDirectory.getBaseDn() + " [" + u.getScheme() + "] enabled.");
+               }
+
+               if (!isRolesDnBase(baseDn)) {
+                       if (userAdminReg != null)
+                               userAdminReg.unregister();
+                       // register self as main user admin
+                       userAdminReg = bc.registerService(UserAdmin.class, this, currentState());
+               }
        }
 
-       private class TransactionManagerStc implements ServiceTrackerCustomizer<TransactionManager, TransactionManager> {
+       private boolean isRolesDnBase(LdapName baseDn) {
+               return baseDn.equals(ROLES_BASE);
+       }
+
+       @Override
+       public void deleted(String pid) {
+               LdapName baseDn = pidToBaseDn.remove(pid);
+               UserAdmin userAdmin = userAdmins.remove(baseDn);
+               ((UserDirectory) userAdmin).destroy();
+       }
+
+       @Override
+       public String getName() {
+               return "Node user admin";
+       }
+
+       private class TransactionManagerStc extends ServiceTracker<TransactionManager, TransactionManager> {
+
+               public TransactionManagerStc() {
+                       super(bc, TransactionManager.class, null);
+               }
 
                @Override
                public TransactionManager addingService(ServiceReference<TransactionManager> reference) {
                        TransactionManager transactionManager = bc.getService(reference);
-                       ((UserDirectory) nodeRoles).setTransactionManager(transactionManager);
+                       if (nodeRoles != null)
+                               ((UserDirectory) nodeRoles).setTransactionManager(transactionManager);
                        for (UserAdmin userAdmin : userAdmins.values()) {
                                if (userAdmin instanceof UserDirectory)
                                        ((UserDirectory) userAdmin).setTransactionManager(transactionManager);
@@ -107,10 +170,6 @@ class NodeUserAdmin implements UserAdmin, ManagedService, KernelConstants {
                        return transactionManager;
                }
 
-               @Override
-               public void modifiedService(ServiceReference<TransactionManager> reference, TransactionManager service) {
-               }
-
                @Override
                public void removedService(ServiceReference<TransactionManager> reference, TransactionManager service) {
                        ((UserDirectory) nodeRoles).setTransactionManager(null);
@@ -122,36 +181,38 @@ class NodeUserAdmin implements UserAdmin, ManagedService, KernelConstants {
 
        }
 
-       @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);
-               }
-
-               // JCR
-               // initJcr(adminSession);
-       }
+       // @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);
+       // }
+       //
+       // // JCR
+       // // initJcr(adminSession);
+       // }
 
        Dictionary<String, Object> currentState() {
                Dictionary<String, Object> res = new Hashtable<String, Object>();
+               res.put(NodeConstants.CN, NodeConstants.DEFAULT);
                for (LdapName name : userAdmins.keySet()) {
                        StringBuilder buf = new StringBuilder();
                        if (userAdmins.get(name) instanceof UserDirectory) {
@@ -243,15 +304,18 @@ class NodeUserAdmin implements UserAdmin, ManagedService, KernelConstants {
        // USER ADMIN AGGREGATOR
        //
        public void addUserAdmin(String baseDn, UserAdmin userAdmin) {
-               if (userAdmins.containsKey(baseDn))
-                       throw new UserDirectoryException("There is already a user admin for " + baseDn);
                try {
-                       userAdmins.put(new LdapName(baseDn), userAdmin);
+                       LdapName key = new LdapName(baseDn);
+                       if (userAdmins.containsKey(key))
+                               throw new UserDirectoryException("There is already a user admin for " + baseDn);
+                       userAdmins.put(key, userAdmin);
                } catch (InvalidNameException e) {
                        throw new UserDirectoryException("Badly formatted base DN " + baseDn, e);
                }
                if (userAdmin instanceof UserDirectory) {
+                       UserDirectory userDirectory = (UserDirectory) userAdmin;
                        try {
+                               userDirectory.setTransactionManager(tmTracker.getService());
                                // FIXME Make it less bitronix dependant
                                EhCacheXAResourceProducer.registerXAResource(cacheName, ((UserDirectory) userAdmin).getXaResource());
                        } catch (Exception e) {
@@ -292,95 +356,105 @@ class NodeUserAdmin implements UserAdmin, ManagedService, KernelConstants {
                }
        }
 
-       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();
-               }
-               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);
-                       }
-                       Dictionary<String, ?> properties = UserAdminConf.uriAsProperties(u.toString());
-                       UserDirectory businessRoles;
-                       if (u.getScheme().startsWith("ldap")) {
-                               businessRoles = new LdapUserAdmin(properties);
-                       } else {
-                               businessRoles = new LdifUserAdmin(properties);
-                       }
-                       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);
-                       }
-                       addUserAdmin(businessRoles.getBaseDn(), (UserAdmin) businessRoles);
-                       if (log.isDebugEnabled())
-                               log.debug("User directory " + businessRoles.getBaseDn() + " [" + u.getScheme() + "] enabled.");
-               }
-
-       }
-
-       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();
-               }
-
-               Dictionary<String, ?> nodeRolesProperties = UserAdminConf.uriAsProperties(nodeRolesUri);
-               if (!nodeRolesProperties.get(UserAdminConf.baseDn.name()).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.");
-
-       }
+       // 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();
+       // // }
+       // 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);
+       // }
+       // Dictionary<String, ?> properties =
+       // UserAdminConf.uriAsProperties(u.toString());
+       // UserDirectory businessRoles;
+       // if (u.getScheme().startsWith("ldap")) {
+       // businessRoles = new LdapUserAdmin(properties);
+       // } else {
+       // businessRoles = new LdifUserAdmin(properties);
+       // }
+       // 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);
+       // }
+       // addUserAdmin(businessRoles.getBaseDn(), (UserAdmin) businessRoles);
+       // if (log.isDebugEnabled())
+       // log.debug("User directory " + businessRoles.getBaseDn() + " [" +
+       // u.getScheme() + "] enabled.");
+       // }
+       //
+       // }
+       //
+       // 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();
+       // }
+       //
+       // Dictionary<String, ?> nodeRolesProperties =
+       // UserAdminConf.uriAsProperties(nodeRolesUri);
+       // if
+       // (!nodeRolesProperties.get(UserAdminConf.baseDn.name()).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
diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/UserDirectoryServiceFactory.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/UserDirectoryServiceFactory.java
new file mode 100644 (file)
index 0000000..0726e50
--- /dev/null
@@ -0,0 +1,51 @@
+package org.argeo.cms.internal.kernel;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Hashtable;
+import java.util.Map;
+
+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.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedServiceFactory;
+
+class UserDirectoryServiceFactory implements ManagedServiceFactory {
+       private final BundleContext bc = FrameworkUtil.getBundle(UserDirectoryServiceFactory.class).getBundleContext();
+
+       private Map<String, UserDirectory> userDirectories = new HashMap<>();
+
+       @Override
+       public String getName() {
+               return "User Directories Factory";
+       }
+
+       @Override
+       public void updated(String pid, Dictionary<String, ?> properties) throws ConfigurationException {
+               String uri = (String) properties.get(UserAdminConf.uri.name());
+               UserDirectory userDirectory = uri.startsWith("ldap:") ? new LdapUserAdmin(properties)
+                               : new LdifUserAdmin(properties);
+               String baseDn = userDirectory.getBaseDn();
+               Dictionary<String, Object> regProps = new Hashtable<>();
+               regProps.put(Constants.SERVICE_PID, pid);
+               regProps.put(UserAdminConf.baseDn.name(), baseDn);
+//             regProps.put(UserAdminConf.uri.name(), uri);
+               bc.registerService(UserDirectory.class, userDirectory, regProps);
+               userDirectories.put(pid, userDirectory);
+       }
+
+       @Override
+       public void deleted(String pid) {
+               userDirectories.remove(pid);
+       }
+
+       void shutdown() {
+               for (UserDirectory userDirectory : userDirectories.values())
+                       userDirectory.destroy();
+       }
+}
index 5a9cd8c410d68afb7b6ed3644140c043388a15a1..316941ea824c0a2aebbb64c16b86dc5301edc8a8 100644 (file)
@@ -14,6 +14,8 @@ import java.util.Map;
 
 import javax.naming.Context;
 
+import org.osgi.framework.Constants;
+
 /** Properties used to configure user admins. */
 public enum UserAdminConf {
        /** Base DN (cannot be configured externally) */
@@ -88,7 +90,10 @@ public enum UserAdminConf {
                boolean first = true;
                for (Enumeration<String> keys = properties.keys(); keys.hasMoreElements();) {
                        String key = keys.nextElement();
-                       if (!key.startsWith("java") && !key.equals(baseDn.name()) && !key.equals(uri.name())) {
+                       // TODO clarify which keys are relevant (list only the enum?)
+                       if (!key.equals("service.factoryPid") && !key.equals("cn") && !key.equals("dn")
+                                       && !key.equals(Constants.SERVICE_PID) && !key.startsWith("java") && !key.equals(baseDn.name())
+                                       && !key.equals(uri.name())) {
                                if (first)
                                        first = false;
                                else
@@ -107,7 +112,7 @@ public enum UserAdminConf {
                }
        }
 
-       public static Dictionary<String, ?> uriAsProperties(String uriStr) {
+       public static Dictionary<String, Object> uriAsProperties(String uriStr) {
                try {
                        Hashtable<String, Object> res = new Hashtable<String, Object>();
                        URI u = new URI(uriStr);