From df8ecf06ff62ff3f31a7cbe7c992e183312563fd Mon Sep 17 00:00:00 2001 From: Mathieu Baudier Date: Tue, 6 Sep 2016 10:40:54 +0000 Subject: [PATCH] Use deploy config for node user admin git-svn-id: https://svn.argeo.org/commons/trunk@9091 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- .../src/org/argeo/node/NodeConstants.java | 10 +- .../cms/internal/kernel/CmsDeployment.java | 1 + .../argeo/cms/internal/kernel/CmsState.java | 10 +- .../cms/internal/kernel/DeployConfig.java | 16 +- .../internal/kernel/FirstInitProperties.java | 74 +++- .../argeo/cms/internal/kernel/NodeLogger.java | 16 +- .../cms/internal/kernel/NodeUserAdmin.java | 362 +++++++++++------- .../kernel/UserDirectoryServiceFactory.java | 51 +++ .../argeo/osgi/useradmin/UserAdminConf.java | 9 +- 9 files changed, 391 insertions(+), 158 deletions(-) create mode 100644 org.argeo.cms/src/org/argeo/cms/internal/kernel/UserDirectoryServiceFactory.java diff --git a/org.argeo.cms.api/src/org/argeo/node/NodeConstants.java b/org.argeo.cms.api/src/org/argeo/node/NodeConstants.java index 039b2f9e9..477b0b96b 100644 --- a/org.argeo.cms.api/src/org/argeo/node/NodeConstants.java +++ b/org.argeo.cms.api/src/org/argeo/node/NodeConstants.java @@ -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"; } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java index 45e218a15..a2d072e5b 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsDeployment.java @@ -118,6 +118,7 @@ public class CmsDeployment implements NodeDeployment { prepareDataModel(KernelUtils.openAdminSession(deployedNodeRepository)); Hashtable regProps = new Hashtable(); + regProps.put(NodeConstants.CN, ArgeoJcrConstants.ALIAS_HOME); regProps.put(ArgeoJcrConstants.JCR_REPOSITORY_ALIAS, ArgeoJcrConstants.ALIAS_HOME); homeRepository = new HomeRepository(deployedNodeRepository); // register diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java index 23d2f266d..87fae05cf 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/CmsState.java @@ -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 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() { diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java index 572631eff..fbe206644 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/DeployConfig.java @@ -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 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> userDirectoryConfigs = firstInit.getUserDirectoryConfigs(); + for (int i = 0; i < userDirectoryConfigs.size(); i++) { + Dictionary userDirectoryConfig = userDirectoryConfigs.get(i); + String cn = Integer.toString(i); + userDirectoryConfig.put(NodeConstants.CN, cn); + putFactoryDeployConfig(NodeConstants.NODE_USER_ADMIN_PID, userDirectoryConfig); + } + + // http server Dictionary 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); diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/FirstInitProperties.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/FirstInitProperties.java index 6b34c207c..2a054d5be 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/FirstInitProperties.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/FirstInitProperties.java @@ -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 getHttpServerConfig(Dictionary 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> getUserDirectoryConfigs() { + List> res = new ArrayList<>(); + File nodeBaseDir = KernelUtils.getOsgiInstancePath(KernelConstants.DIR_NODE).toFile(); + List 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 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). diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java index 3de2c7934..4f58e7525 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeLogger.java @@ -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(); } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java index fd9ba31df..c04d820da 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/NodeUserAdmin.java @@ -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 userAdmins = new HashMap(); + private Map pidToBaseDn = new HashMap<>(); + + private ServiceRegistration userAdminReg; + + private final ServiceTracker 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 properties) throws ConfigurationException { + public void updated(String pid, Dictionary 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 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 { + 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 { + + public TransactionManagerStc() { + super(bc, TransactionManager.class, null); + } @Override public TransactionManager addingService(ServiceReference 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 reference, TransactionManager service) { - } - @Override public void removedService(ServiceReference 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 currentState() { Dictionary res = new Hashtable(); + 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 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 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 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 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 index 000000000..0726e5029 --- /dev/null +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/UserDirectoryServiceFactory.java @@ -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 userDirectories = new HashMap<>(); + + @Override + public String getName() { + return "User Directories Factory"; + } + + @Override + public void updated(String pid, Dictionary 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 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(); + } +} diff --git a/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminConf.java b/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminConf.java index 5a9cd8c41..316941ea8 100644 --- a/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminConf.java +++ b/org.argeo.security.core/src/org/argeo/osgi/useradmin/UserAdminConf.java @@ -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 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 uriAsProperties(String uriStr) { + public static Dictionary uriAsProperties(String uriStr) { try { Hashtable res = new Hashtable(); URI u = new URI(uriStr); -- 2.30.2