Make CMS running without data area, and remove unnecessary dependencies.
authorMathieu Baudier <mbaudier@argeo.org>
Wed, 20 Jul 2022 09:37:07 +0000 (11:37 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Wed, 20 Jul 2022 09:37:07 +0000 (11:37 +0200)
17 files changed:
org.argeo.api.cms/src/org/argeo/api/cms/CmsConstants.java
org.argeo.cms/src/org/argeo/cms/acr/MountManager.java
org.argeo.cms/src/org/argeo/cms/acr/xml/DomContentProvider.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsContextImpl.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/DeployedContentRepository.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/KernelUtils.java
org.argeo.cms/src/org/argeo/cms/osgi/BundleCmsTheme.java
org.argeo.cms/src/org/argeo/cms/runtime/StaticCms.java
org.argeo.cms/src/org/argeo/cms/security/AbstractKeyring.java
org.argeo.util/src/org/argeo/osgi/useradmin/AggregatingUserAdmin.java
org.argeo.util/src/org/argeo/util/FsUtils.java
org.argeo.util/src/org/argeo/util/StreamUtils.java
org.argeo.util/src/org/argeo/util/directory/DirectoryConf.java
org.argeo.util/src/org/argeo/util/directory/ldap/AbstractLdapDirectory.java
org.argeo.util/src/org/argeo/util/directory/ldap/LdifDao.java

index 207b0a8df98b7d44419d3aa505fae663fb6fa334..98364d97b9781220cb3f1c4e2725dd4ed1f143a2 100644 (file)
@@ -86,33 +86,9 @@ public interface CmsConstants {
        String EVENT_TOPICS = "event.topics";
 
        /*
-        * INIT FRAMEWORK PROPERTIES
+        * FILE SYSTEM
         */
-//     String NODE_INIT = "argeo.node.init";
-//     String I18N_DEFAULT_LOCALE = "argeo.i18n.defaultLocale";
-//     String I18N_LOCALES = "argeo.i18n.locales";
-       // Node Security
-//     String ROLES_URI = "argeo.node.roles.uri";
-//     String TOKENS_URI = "argeo.node.tokens.uri";
-//     /** URI to an LDIF file or LDAP server used as initialization or backend */
-//     String USERADMIN_URIS = "argeo.node.useradmin.uris";
-       // Transaction manager
-//     String TRANSACTION_MANAGER = "argeo.node.transaction.manager";
-//     String TRANSACTION_MANAGER_SIMPLE = "simple";
-//     String TRANSACTION_MANAGER_BITRONIX = "bitronix";
-       // Node
-//     /** Properties configuring the node repository */
-//     String NODE_REPO_PROP_PREFIX = "argeo.node.repo.";
-//     /** Additional standalone repositories, related to data models. */
-//     String NODE_REPOS_PROP_PREFIX = "argeo.node.repos.";
-       // HTTP
-//     String HTTP_PORT = "org.osgi.service.http.port";
-//     String HTTP_PORT_SECURE = "org.osgi.service.http.port.secure";
-//     /**
-//      * The HTTP header used to convey the DN of a client verified by a reverse
-//      * proxy. Typically SSL_CLIENT_S_DN for Apache.
-//      */
-//     String HTTP_PROXY_SSL_DN = "argeo.http.proxy.ssl.dn";
+       String CMS_FS_SCHEME = "cms";
 
        /*
         * PIDs
index 6a6dcaacbe795ffa836f25f7738f62884f291310..69b76ddc641f859bafb0ca2083b7ab9ccc5b1805 100644 (file)
@@ -52,6 +52,8 @@ class MountManager {
                if (entry == null)
                        throw new IllegalArgumentException("No entry provider found for " + path);
                String mountPath = entry.getKey();
+               if (!path.startsWith(mountPath))
+                       throw new IllegalArgumentException("Path " + path + " doesn't have a content provider");
                ContentProvider contentProvider = entry.getValue();
                assert mountPath.equals(contentProvider.getMountPath());
                return contentProvider;
index 54013e2ad1301deb66235671fcce278e6be64b58..d6e246df53fb9282c9171cc8e2fd977b12a07b4b 100644 (file)
@@ -15,6 +15,7 @@ import javax.xml.xpath.XPathFactory;
 
 import org.argeo.api.acr.Content;
 import org.argeo.api.acr.ContentNotFoundException;
+import org.argeo.api.acr.CrName;
 import org.argeo.api.acr.NamespaceUtils;
 import org.argeo.api.acr.spi.ContentProvider;
 import org.argeo.api.acr.spi.ProvidedContent;
@@ -79,7 +80,7 @@ public class DomContentProvider implements ContentProvider, NamespaceContext {
                        throw new IllegalArgumentException("Relative path cannot start with /");
                String xPathExpression = '/' + relativePath;
                if ("/".equals(mountPath))
-                       xPathExpression = "/cr:root" + xPathExpression;
+                       xPathExpression = "/" + CrName.root.qName() + xPathExpression;
                try {
                        NodeList nodes = (NodeList) xPath.get().evaluate(xPathExpression, document, XPathConstants.NODESET);
                        return nodes;
index ea9a401a4d3fc49ee2f617558432dbc11f170024..7a0f3388c07a4f79cabdd6928de9fa210e3bc511 100644 (file)
@@ -3,7 +3,6 @@ package org.argeo.cms.internal.runtime;
 import java.lang.management.ManagementFactory;
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
index d335b48b191b111ce428ac2bab5dc19beff228e8..fd2c5f9cdb47d4632ae7b9cf8464e92f3bdb94d9 100644 (file)
@@ -1,7 +1,5 @@
 package org.argeo.cms.internal.runtime;
 
-import java.io.File;
-import java.io.FileFilter;
 import java.io.IOException;
 import java.io.Reader;
 import java.net.URL;
@@ -23,13 +21,13 @@ import java.util.UUID;
 
 import javax.security.auth.login.Configuration;
 
-import org.apache.commons.io.FileUtils;
 import org.argeo.api.cms.CmsConstants;
 import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.CmsState;
 import org.argeo.api.uuid.UuidFactory;
 import org.argeo.cms.CmsDeployProperty;
 import org.argeo.cms.auth.ident.IdentClient;
+import org.argeo.util.FsUtils;
 
 /**
  * Implementation of a {@link CmsState}, initialising the required services.
@@ -57,12 +55,16 @@ public class CmsStateImpl implements CmsState {
                deployPropertyDefaults.put(CmsDeployProperty.SSL_KEYSTORETYPE, PkiUtils.PKCS12);
                deployPropertyDefaults.put(CmsDeployProperty.SSL_PASSWORD, PkiUtils.DEFAULT_KEYSTORE_PASSWORD);
                Path keyStorePath = getDataPath(PkiUtils.DEFAULT_KEYSTORE_PATH);
-               deployPropertyDefaults.put(CmsDeployProperty.SSL_KEYSTORE, keyStorePath.toAbsolutePath().toString());
+               if (keyStorePath != null) {
+                       deployPropertyDefaults.put(CmsDeployProperty.SSL_KEYSTORE, keyStorePath.toAbsolutePath().toString());
+               }
 
                Path trustStorePath = getDataPath(PkiUtils.DEFAULT_TRUSTSTORE_PATH);
+               if (trustStorePath != null) {
+                       deployPropertyDefaults.put(CmsDeployProperty.SSL_TRUSTSTORE, trustStorePath.toAbsolutePath().toString());
+               }
                deployPropertyDefaults.put(CmsDeployProperty.SSL_TRUSTSTORETYPE, PkiUtils.PKCS12);
                deployPropertyDefaults.put(CmsDeployProperty.SSL_TRUSTSTOREPASSWORD, PkiUtils.DEFAULT_KEYSTORE_PASSWORD);
-               deployPropertyDefaults.put(CmsDeployProperty.SSL_TRUSTSTORE, trustStorePath.toAbsolutePath().toString());
 
                this.deployPropertyDefaults = Collections.unmodifiableMap(deployPropertyDefaults);
        }
@@ -110,9 +112,8 @@ public class CmsStateImpl implements CmsState {
                                log.debug("## CMS starting... (" + uuid + ")\n" + sb + "\n");
                        }
 
-//             initI18n();
-//             initServices();
-                       if (!Files.exists(getDataPath(CmsConstants.NODE))) {// first init
+                       Path nodeBase = getDataPath(CmsConstants.NODE);
+                       if (nodeBase != null && !Files.exists(nodeBase)) {// first init
                                firstInit();
                        }
 
@@ -351,7 +352,7 @@ public class CmsStateImpl implements CmsState {
        public static void prepareFirstInitInstanceArea(List<String> nodeInits) {
 
                for (String nodeInit : nodeInits) {
-                       if(nodeInit==null)
+                       if (nodeInit == null)
                                continue;
 
                        if (nodeInit.startsWith("http")) {
@@ -360,29 +361,17 @@ public class CmsStateImpl implements CmsState {
                        } else {
 
                                // TODO use java.nio.file
-                               File initDir;
+                               Path initDir;
                                if (nodeInit.startsWith("."))
                                        initDir = KernelUtils.getExecutionDir(nodeInit);
                                else
-                                       initDir = new File(nodeInit);
+                                       initDir = Paths.get(nodeInit);
                                // TODO also uncompress archives
-                               if (initDir.exists())
-                                       try {
-                                               // TODO use NIO utilities
-                                               FileUtils.copyDirectory(initDir, KernelUtils.getOsgiInstancePath("").toFile(),
-                                                               new FileFilter() {
-
-                                                                       @Override
-                                                                       public boolean accept(File pathname) {
-                                                                               if (pathname.getName().equals(".svn") || pathname.getName().equals(".git"))
-                                                                                       return false;
-                                                                               return true;
-                                                                       }
-                                                               });
-                                               log.info("CMS initialized from " + initDir.getCanonicalPath());
-                                       } catch (IOException e) {
-                                               throw new RuntimeException("Cannot initialize from " + initDir, e);
-                                       }
+                               if (Files.exists(initDir)) {
+                                       Path dataPath = KernelUtils.getOsgiInstancePath("");
+                                       FsUtils.copyDirectory(initDir, dataPath);
+                                       log.info("CMS initialized from " + initDir);
+                               }
                        }
                }
        }
index 4f0ba10aad03d6432d94603353f26e343adc5a76..ab98c062585684c9a536dc95a20644d7208dc1bf 100644 (file)
@@ -1,6 +1,5 @@
 package org.argeo.cms.internal.runtime;
 
-import java.io.File;
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.URI;
@@ -8,6 +7,7 @@ import java.net.URISyntaxException;
 import java.net.URL;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.security.PrivilegedExceptionAction;
 import java.util.ArrayList;
 import java.util.Dictionary;
@@ -25,7 +25,6 @@ import javax.security.auth.kerberos.KerberosPrincipal;
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
 
-import org.apache.commons.io.FileUtils;
 import org.argeo.api.cms.CmsAuth;
 import org.argeo.api.cms.CmsConstants;
 import org.argeo.api.cms.CmsLog;
@@ -89,42 +88,42 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
 
        protected List<Dictionary<String, Object>> getUserDirectoryConfigs() {
                List<Dictionary<String, Object>> res = new ArrayList<>();
-               File nodeBaseDir = cmsState.getDataPath(KernelConstants.DIR_NODE).toFile();
+               Path nodeBase = cmsState.getDataPath(KernelConstants.DIR_NODE);
                List<String> uris = new ArrayList<>();
 
                // node roles
                String nodeRolesUri = null;// getFrameworkProp(CmsConstants.ROLES_URI);
                String baseNodeRoleDn = CmsConstants.ROLES_BASEDN;
-               if (nodeRolesUri == null) {
+               if (nodeRolesUri == null && nodeBase != null) {
                        nodeRolesUri = baseNodeRoleDn + ".ldif";
-                       File nodeRolesFile = new File(nodeBaseDir, nodeRolesUri);
-                       if (!nodeRolesFile.exists())
+                       Path nodeRolesFile = nodeBase.resolve(nodeRolesUri);
+                       if (!Files.exists(nodeRolesFile))
                                try {
-                                       FileUtils.copyInputStreamToFile(CmsUserAdmin.class.getResourceAsStream(baseNodeRoleDn + ".ldif"),
-                                                       nodeRolesFile);
+                                       Files.copy(CmsUserAdmin.class.getResourceAsStream(baseNodeRoleDn + ".ldif"), nodeRolesFile);
                                } catch (IOException e) {
                                        throw new RuntimeException("Cannot copy demo resource", e);
                                }
                        // nodeRolesUri = nodeRolesFile.toURI().toString();
                }
-               uris.add(nodeRolesUri);
+               if (nodeRolesUri != null)
+                       uris.add(nodeRolesUri);
 
                // node tokens
                String nodeTokensUri = null;// getFrameworkProp(CmsConstants.TOKENS_URI);
                String baseNodeTokensDn = CmsConstants.TOKENS_BASEDN;
-               if (nodeTokensUri == null) {
+               if (nodeTokensUri == null && nodeBase != null) {
                        nodeTokensUri = baseNodeTokensDn + ".ldif";
-                       File nodeTokensFile = new File(nodeBaseDir, nodeTokensUri);
-                       if (!nodeTokensFile.exists())
+                       Path nodeTokensFile = nodeBase.resolve(nodeTokensUri);
+                       if (!Files.exists(nodeTokensFile))
                                try {
-                                       FileUtils.copyInputStreamToFile(CmsUserAdmin.class.getResourceAsStream(baseNodeTokensDn + ".ldif"),
-                                                       nodeTokensFile);
+                                       Files.copy(CmsUserAdmin.class.getResourceAsStream(baseNodeTokensDn + ".ldif"), nodeTokensFile);
                                } catch (IOException e) {
                                        throw new RuntimeException("Cannot copy demo resource", e);
                                }
                        // nodeRolesUri = nodeRolesFile.toURI().toString();
                }
-               uris.add(nodeTokensUri);
+               if (nodeTokensUri != null)
+                       uris.add(nodeTokensUri);
 
                // Business roles
 //             String userAdminUris = getFrameworkProp(CmsConstants.USERADMIN_URIS);
@@ -136,19 +135,17 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
                        uris.add(userAdminUri);
                }
 
-               if (uris.size() == 0) {
+               if (uris.size() == 0 && nodeBase != null) {
                        // TODO put this somewhere else
                        String demoBaseDn = "dc=example,dc=com";
                        String userAdminUri = demoBaseDn + ".ldif";
-                       File businessRolesFile = new File(nodeBaseDir, userAdminUri);
-                       File systemRolesFile = new File(nodeBaseDir, "ou=roles,ou=node.ldif");
-                       if (!businessRolesFile.exists())
+                       Path businessRolesFile = nodeBase.resolve(userAdminUri);
+                       Path systemRolesFile = nodeBase.resolve("ou=roles,ou=node.ldif");
+                       if (!Files.exists(businessRolesFile))
                                try {
-                                       FileUtils.copyInputStreamToFile(CmsUserAdmin.class.getResourceAsStream(demoBaseDn + ".ldif"),
-                                                       businessRolesFile);
-                                       if (!systemRolesFile.exists())
-                                               FileUtils.copyInputStreamToFile(
-                                                               CmsUserAdmin.class.getResourceAsStream("example-ou=roles,ou=node.ldif"),
+                                       Files.copy(CmsUserAdmin.class.getResourceAsStream(demoBaseDn + ".ldif"), businessRolesFile);
+                                       if (!Files.exists(systemRolesFile))
+                                               Files.copy(CmsUserAdmin.class.getResourceAsStream("example-ou=roles,ou=node.ldif"),
                                                                systemRolesFile);
                                } catch (IOException e) {
                                        throw new RuntimeException("Cannot copy demo resources", e);
@@ -168,14 +165,14 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
                                                        "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();
+                                               u = Paths.get(uri).toRealPath().toUri();
                                        else if (!uri.contains("/")) {
                                                // u = KernelUtils.getOsgiInstanceUri(KernelConstants.DIR_NODE + '/' + uri);
                                                u = new URI(uri);
                                        } else
                                                throw new IllegalArgumentException("Cannot interpret " + uri + " as an uri");
                                } else if (u.getScheme().equals(DirectoryConf.SCHEME_FILE)) {
-                                       u = new File(u).getCanonicalFile().toURI();
+                                       u = Paths.get(u).toRealPath().toUri();
                                }
                        } catch (Exception e) {
                                throw new RuntimeException("Cannot interpret " + uri + " as an uri", e);
index 72a30fb083b032f0f6f10838bf6fc1523418b253..8358105e2982db480f79369db507b14f471b0d90 100644 (file)
@@ -31,9 +31,11 @@ public class DeployedContentRepository extends CmsContentRepository {
 
                        // run dir
                        Path runDirPath = KernelUtils.getOsgiInstancePath(CmsContentRepository.RUN_BASE);
-                       Files.createDirectories(runDirPath);
-                       FsContentProvider runContentProvider = new FsContentProvider(CmsContentRepository.RUN_BASE, runDirPath);
-                       addProvider(runContentProvider);
+                       if (runDirPath != null) {
+                               Files.createDirectories(runDirPath);
+                               FsContentProvider runContentProvider = new FsContentProvider(CmsContentRepository.RUN_BASE, runDirPath);
+                               addProvider(runContentProvider);
+                       }
 
                        // users
                        DirectoryContentProvider directoryContentProvider = new DirectoryContentProvider(
index 0e84af62af45d8c5b2d22b0261cb3e1dcc2170b9..295578f535a3711fdf90bcab95fab58433c6042f 100644 (file)
@@ -1,6 +1,5 @@
 package org.argeo.cms.internal.runtime;
 
-import java.io.File;
 import java.io.IOException;
 import java.io.PrintStream;
 import java.net.URI;
@@ -52,12 +51,12 @@ class KernelUtils implements KernelConstants {
                return asDictionary(props);
        }
 
-       static File getExecutionDir(String relativePath) {
-               File executionDir = new File(getFrameworkProp("user.dir"));
+       static Path getExecutionDir(String relativePath) {
+               Path executionDir = Paths.get(getFrameworkProp("user.dir"));
                if (relativePath == null)
                        return executionDir;
                try {
-                       return new File(executionDir, relativePath).getCanonicalFile();
+                       return executionDir.resolve(relativePath).toRealPath();
                } catch (IOException e) {
                        throw new IllegalArgumentException("Cannot get canonical file", e);
                }
@@ -69,28 +68,34 @@ class KernelUtils implements KernelConstants {
 //     }
 
        public static Path getOsgiInstancePath(String relativePath) {
-               return Paths.get(getOsgiInstanceUri(relativePath));
+               URI uri = getOsgiInstanceUri(relativePath);
+               if (uri == null) // no data area available
+                       return null;
+               return Paths.get(uri);
        }
 
        public static URI getOsgiInstanceUri(String relativePath) {
                String osgiInstanceBaseUri = getFrameworkProp(OSGI_INSTANCE_AREA);
+               if (osgiInstanceBaseUri == null) // no data area available
+                       return null;
+
                if (!osgiInstanceBaseUri.endsWith("/"))
                        osgiInstanceBaseUri = osgiInstanceBaseUri + "/";
-               if (osgiInstanceBaseUri != null)
-                       return safeUri(osgiInstanceBaseUri + (relativePath != null ? relativePath : ""));
-               else
-                       return Paths.get(System.getProperty("user.dir"), (relativePath != null ? relativePath : "")).toUri();
+//             if (osgiInstanceBaseUri != null)
+               return safeUri(osgiInstanceBaseUri + (relativePath != null ? relativePath : ""));
+//             else
+//                     return Paths.get(System.getProperty("user.dir"), (relativePath != null ? relativePath : "")).toUri();
        }
 
-       static File getOsgiConfigurationFile(String relativePath) {
-               try {
-                       return new File(
-                                       new URI(CmsActivator.getBundleContext().getProperty(OSGI_CONFIGURATION_AREA) + relativePath))
-                                       .getCanonicalFile();
-               } catch (Exception e) {
-                       throw new IllegalArgumentException("Cannot get configuration file for " + relativePath, e);
-               }
-       }
+//     static File getOsgiConfigurationFile(String relativePath) {
+//             try {
+//                     return new File(
+//                                     new URI(CmsActivator.getBundleContext().getProperty(OSGI_CONFIGURATION_AREA) + relativePath))
+//                                     .getCanonicalFile();
+//             } catch (Exception e) {
+//                     throw new IllegalArgumentException("Cannot get configuration file for " + relativePath, e);
+//             }
+//     }
 
        static String getFrameworkProp(String key, String def) {
                String value;
index 3ab799f713e1ab9e802a20654efc81426c7de5b7..de7eec8c2a39e19ea93faa507a8b1ef6fc2aa4b8 100644 (file)
@@ -7,7 +7,6 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.URL;
-import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.HashSet;
@@ -17,8 +16,8 @@ import java.util.Set;
 import java.util.TreeSet;
 import java.util.stream.Collectors;
 
-import org.apache.commons.io.IOUtils;
 import org.argeo.api.cms.ux.CmsTheme;
+import org.argeo.util.StreamUtils;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleContext;
 
@@ -213,7 +212,7 @@ public class BundleCmsTheme implements CmsTheme {
 
        void loadBodyHtml(URL url) {
                try (BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), UTF_8))) {
-                       bodyHtml = IOUtils.toString(url, StandardCharsets.UTF_8);
+                       bodyHtml = StreamUtils.toString(in);
                } catch (IOException e) {
                        throw new IllegalArgumentException("Cannot load URL " + url, e);
                }
index d1a19bd63a1af6d395d53e6312b8048270b91361..e473d27994ff8f4e467461166b3b6523c7043fb5 100644 (file)
@@ -31,7 +31,7 @@ import org.osgi.service.useradmin.UserAdmin;
  * deployment. Useful for testing or AOT compilation.
  */
 public class StaticCms {
-       private static SimpleRegister register = new SimpleRegister();
+       private SimpleRegister register = new SimpleRegister();
 
        private CompletableFuture<Void> stopped = new CompletableFuture<Void>();
 
@@ -51,14 +51,6 @@ public class StaticCms {
                                .addDependency(uuidFactoryC.getType(UuidFactory.class), cmsState::setUuidFactory, null) //
                                .build(register);
 
-               // Deployment Configuration
-//             DeployConfig deployConfig = new DeployConfig();
-//             Component<DeployConfig> deployConfigC = new Component.Builder<>(deployConfig) //
-//                             .addType(DeployConfig.class) //
-//                             .addActivation(deployConfig::start) //
-//                             .addDeactivation(deployConfig::stop) //
-//                             .build(register);
-
                // Transaction manager
                SimpleTransactionManager transactionManager = new SimpleTransactionManager();
                Component<SimpleTransactionManager> transactionManagerC = new Component.Builder<>(transactionManager) //
@@ -75,10 +67,6 @@ public class StaticCms {
                                .addDependency(cmsStateC.getType(CmsState.class), userAdmin::setCmsState, null) //
                                .addDependency(transactionManagerC.getType(WorkControl.class), userAdmin::setTransactionManager, null) //
                                .addDependency(transactionManagerC.getType(WorkTransaction.class), userAdmin::setUserTransaction, null) //
-//                             .addDependency(deployConfigC.getType(DeployConfig.class), (d) -> {
-//                                     for (Dictionary<String, Object> userDirectoryConfig : d.getUserDirectoryConfigs())
-//                                             userAdmin.enableUserDirectory(userDirectoryConfig);
-//                             }, null) //
                                .build(register);
 
                // User manager
index 10b583fdfa6b9e5eba23c91fe8b052a1dd96c294..3de2e1451d89a5a7b5cafb16d2cbe54194d2e2aa 100644 (file)
@@ -24,9 +24,9 @@ import javax.security.auth.callback.UnsupportedCallbackException;
 import javax.security.auth.login.LoginContext;
 import javax.security.auth.login.LoginException;
 
-import org.apache.commons.io.IOUtils;
 import org.argeo.api.cms.CmsAuth;
 import org.argeo.util.CurrentSubject;
+import org.argeo.util.StreamUtils;
 
 /** username / password based keyring. TODO internationalize */
 public abstract class AbstractKeyring implements Keyring, CryptoKeyring {
@@ -109,7 +109,7 @@ public abstract class AbstractKeyring implements Keyring, CryptoKeyring {
                try (InputStream in = getAsStream(path);
                                CharArrayWriter writer = new CharArrayWriter();
                                Reader reader = new InputStreamReader(in, charset);) {
-                       IOUtils.copy(reader, writer);
+                       StreamUtils.copy(reader, writer);
                        return writer.toCharArray();
                } catch (IOException e) {
                        throw new IllegalStateException("Cannot decrypt to char array", e);
index c1727f7465d2e4fbdde2bdeea3671cc51da90fc0..ef253800ca304d9b3af6302b1e4df365a65c7af6 100644 (file)
@@ -6,6 +6,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -14,6 +15,7 @@ import java.util.TreeSet;
 import javax.naming.InvalidNameException;
 import javax.naming.ldap.LdapName;
 
+import org.argeo.util.directory.DirectoryConf;
 import org.osgi.framework.InvalidSyntaxException;
 import org.osgi.service.useradmin.Authorization;
 import org.osgi.service.useradmin.Group;
@@ -251,7 +253,12 @@ public class AggregatingUserAdmin implements UserAdmin {
 //     }
 
        public void start() {
-
+               if (systemRoles == null) {
+                       // TODO do we really need separate system roles?
+                       Hashtable<String, Object> properties = new Hashtable<>();
+                       properties.put(DirectoryConf.baseDn.name(), "ou=roles,ou=system");
+                       systemRoles = new DirectoryUserAdmin(properties);
+               }
        }
 
        public void stop() {
index b317f4bc95bbfaa6570487c614e9bc8225276849..23839db74c3f93c8c2f82a740089c39499b756d8 100644 (file)
@@ -9,6 +9,43 @@ import java.nio.file.attribute.BasicFileAttributes;
 
 /** Utilities around the standard Java file abstractions. */
 public class FsUtils {
+
+       /**
+        * Deletes this path, recursively if needed. Does nothing if the path does not
+        * exist.
+        */
+       public static void copyDirectory(Path source, Path target) {
+               if (!Files.exists(source) || !Files.isDirectory(source))
+                       throw new IllegalArgumentException(source + " is not a directory");
+               if (Files.exists(target) && !Files.isDirectory(target))
+                       throw new IllegalArgumentException(target + " is not a directory");
+               try {
+                       Files.createDirectories(target);
+                       Files.walkFileTree(source, new SimpleFileVisitor<Path>() {
+                               @Override
+                               public FileVisitResult postVisitDirectory(Path directory, IOException e) throws IOException {
+                                       if (e != null)
+                                               throw e;
+                                       Path relativePath = source.relativize(directory);
+                                       Path targetDirectory = target.resolve(relativePath);
+                                       Files.createDirectory(targetDirectory);
+                                       return FileVisitResult.CONTINUE;
+                               }
+
+                               @Override
+                               public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
+                                       Path relativePath = source.relativize(file);
+                                       Path targetFile = target.resolve(relativePath);
+                                       Files.copy(file, targetFile);
+                                       return FileVisitResult.CONTINUE;
+                               }
+                       });
+               } catch (IOException e) {
+                       throw new RuntimeException("Cannot copy " + source + " to " + target, e);
+               }
+
+       }
+
        /**
         * Deletes this path, recursively if needed. Does nothing if the path does not
         * exist.
index 6d7d940ceaf74ea3b9dd60682688cb918ef6c9ff..30404f1e4edc195b9270488b1b0ed41eb7056187 100644 (file)
@@ -1,13 +1,15 @@
 package org.argeo.util;
 
+import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.Reader;
 import java.io.Writer;
+import java.util.StringJoiner;
 
-/** Utilities to be used when Apache Commons IO is not available. */
-class StreamUtils {
+/** Stream utilities to be used when Apache Commons IO is not available. */
+public class StreamUtils {
        private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
 
        /*
@@ -15,8 +17,7 @@ class StreamUtils {
         */
 
        /** @return the number of bytes */
-       public static Long copy(InputStream in, OutputStream out)
-                       throws IOException {
+       public static Long copy(InputStream in, OutputStream out) throws IOException {
                Long count = 0l;
                byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
                while (true) {
@@ -78,4 +79,12 @@ class StreamUtils {
                                //
                        }
        }
+
+       public static String toString(BufferedReader reader) throws IOException {
+               StringJoiner sn = new StringJoiner("\n");
+               String line = null;
+               while ((line = reader.readLine()) != null)
+                       sn.add(line);
+               return sn.toString();
+       }
 }
index c0f96ee75309077ca493c32b21ac00cdc46c3154..4450ca4743242c2d8d29738b2c43b5189ed44e93 100644 (file)
@@ -15,10 +15,10 @@ import org.argeo.util.naming.NamingUtils;
 /** Properties used to configure user admins. */
 public enum DirectoryConf {
        /** Base DN (cannot be configured externally) */
-       baseDn("dc=example,dc=com"),
+       baseDn(null),
 
        /** URI of the underlying resource (cannot be configured externally) */
-       uri("ldap://localhost:10389"),
+       uri(null),
 
        /** User objectClass */
        userObjectClass("inetOrgPerson"),
index 71a87887b85c7fd066d0230b341a312315caa1c7..36047d53e7e8786751fb0547fb1247346ab07e47 100644 (file)
@@ -66,7 +66,11 @@ public abstract class AbstractLdapDirectory implements Directory, XAResourceProv
                        String key = keys.nextElement();
                        configProperties.put(key, props.get(key));
                }
-               baseDn = toLdapName(DirectoryConf.baseDn.getValue(configProperties));
+
+               String baseDnStr = DirectoryConf.baseDn.getValue(configProperties);
+               if (baseDnStr == null)
+                       throw new IllegalArgumentException("Base DN must be specified: " + configProperties);
+               baseDn = toLdapName(baseDnStr);
                this.scoped = scoped;
 
                if (uriArg != null) {
@@ -119,19 +123,26 @@ public abstract class AbstractLdapDirectory implements Directory, XAResourceProv
                        // TODO manage generic redundant LDAP case
                        directoryDao = new LdapDao(this);
                } else {
-                       URI u = URI.create(uri);
-                       if (DirectoryConf.SCHEME_LDAP.equals(u.getScheme()) || DirectoryConf.SCHEME_LDAPS.equals(u.getScheme())) {
-                               directoryDao = new LdapDao(this);
-                       } else if (DirectoryConf.SCHEME_FILE.equals(u.getScheme())) {
-                               directoryDao = new LdifDao(this);
-                       } else if (DirectoryConf.SCHEME_OS.equals(u.getScheme())) {
-                               directoryDao = new OsUserDirectory(this);
-                               // singleUser = true;
+                       if (uri != null) {
+                               URI u = URI.create(uri);
+                               if (DirectoryConf.SCHEME_LDAP.equals(u.getScheme())
+                                               || DirectoryConf.SCHEME_LDAPS.equals(u.getScheme())) {
+                                       directoryDao = new LdapDao(this);
+                               } else if (DirectoryConf.SCHEME_FILE.equals(u.getScheme())) {
+                                       directoryDao = new LdifDao(this);
+                               } else if (DirectoryConf.SCHEME_OS.equals(u.getScheme())) {
+                                       directoryDao = new OsUserDirectory(this);
+                                       // singleUser = true;
+                               } else {
+                                       throw new IllegalArgumentException("Unsupported scheme " + u.getScheme());
+                               }
                        } else {
-                               throw new IllegalArgumentException("Unsupported scheme " + u.getScheme());
+                               // in memory
+                               directoryDao = new LdifDao(this);
                        }
                }
-               xaResource = new WorkingCopyXaResource<>(directoryDao);
+               if (directoryDao != null)
+                       xaResource = new WorkingCopyXaResource<>(directoryDao);
        }
 
        /*
@@ -256,11 +267,12 @@ public abstract class AbstractLdapDirectory implements Directory, XAResourceProv
                                        LdapEntry group = doGetRole(groupDn);
                                        if (group != null) {
                                                allRoles.add(group);
-                                       }else {
+                                       } else {
                                                // user doesn't have the right to retrieve role, but we know it exists
                                                // otherwise memberOf would not work
                                                Attributes a = new BasicAttributes();
-                                               a.put(LdapNameUtils.getLastRdn(groupDn).getType(), LdapNameUtils.getLastRdn(groupDn).getValue());
+                                               a.put(LdapNameUtils.getLastRdn(groupDn).getType(),
+                                                               LdapNameUtils.getLastRdn(groupDn).getValue());
                                                a.put(LdapAttrs.objectClass.name(), LdapObjs.groupOfNames.name());
                                                group = newGroup(groupDn, a);
                                                allRoles.add(group);
@@ -378,7 +390,7 @@ public abstract class AbstractLdapDirectory implements Directory, XAResourceProv
        protected boolean isExternal(LdapName name) {
                return !name.startsWith(baseDn);
        }
-       
+
        protected static boolean hasObjectClass(Attributes attrs, LdapObjs objectClass) {
                return hasObjectClass(attrs, objectClass.name());
        }
index 7387d9e0f9cd52f735ec94625fa296380431d259..d74ac166fc72075adb08008885344d4ac565e240 100644 (file)
@@ -35,65 +35,20 @@ import org.osgi.service.useradmin.Role;
 
 /** A user admin based on a LDIF files. */
 public class LdifDao extends AbstractLdapDirectoryDao {
-//     private NavigableMap<LdapName, LdapEntry> users = new TreeMap<>();
-//     private NavigableMap<LdapName, LdapEntry> groups = new TreeMap<>();
        private NavigableMap<LdapName, LdapEntry> entries = new TreeMap<>();
 
        private NavigableMap<LdapName, LdapHierarchyUnit> hierarchy = new TreeMap<>();
-//     private List<HierarchyUnit> rootHierarchyUnits = new ArrayList<>();
-
-//     public LdifUserAdmin(String uri, String baseDn) {
-//             this(fromUri(uri, baseDn), false);
-//     }
 
        public LdifDao(AbstractLdapDirectory directory) {
                super(directory);
        }
 
-//     protected LdifUserAdmin(Hashtable<String, ?> properties, boolean scoped) {
-//             super( properties, scoped);
-//     }
-
-//     public LdifUserAdmin(URI uri, Dictionary<String, ?> properties) {
-//             super(uri, properties, false);
-//     }
-
-//     @Override
-//     protected AbstractUserDirectory scope(User user) {
-//             Dictionary<String, Object> credentials = user.getCredentials();
-//             String username = (String) credentials.get(SHARED_STATE_USERNAME);
-//             if (username == null)
-//                     username = user.getName();
-//             Object pwdCred = credentials.get(SHARED_STATE_PASSWORD);
-//             byte[] pwd = (byte[]) pwdCred;
-//             if (pwd != null) {
-//                     char[] password = DirectoryDigestUtils.bytesToChars(pwd);
-//                     User directoryUser = (User) getRole(username);
-//                     if (!directoryUser.hasCredential(null, password))
-//                             throw new IllegalStateException("Invalid credentials");
-//             } else {
-//                     throw new IllegalStateException("Password is required");
-//             }
-//             Dictionary<String, Object> properties = cloneProperties();
-//             properties.put(DirectoryConf.readOnly.name(), "true");
-//             LdifUserAdmin scopedUserAdmin = new LdifUserAdmin(properties, true);
-////           scopedUserAdmin.groups = Collections.unmodifiableNavigableMap(groups);
-////           scopedUserAdmin.users = Collections.unmodifiableNavigableMap(users);
-//             scopedUserAdmin.entries = Collections.unmodifiableNavigableMap(entries);
-//             return scopedUserAdmin;
-//     }
-
-//     private static Dictionary<String, Object> fromUri(String uri, String baseDn) {
-//             Hashtable<String, Object> res = new Hashtable<String, Object>();
-//             res.put(DirectoryConf.uri.name(), uri);
-//             res.put(DirectoryConf.baseDn.name(), baseDn);
-//             return res;
-//     }
-
        public void init() {
-
+               String uri = getDirectory().getUri();
+               if (uri == null)
+                       return;
                try {
-                       URI u = new URI(getDirectory().getUri());
+                       URI u = new URI(uri);
                        if (u.getScheme().equals("file")) {
                                File file = new File(u);
                                if (!file.exists())
@@ -107,7 +62,7 @@ public class LdifDao extends AbstractLdapDirectoryDao {
 
        public void save() {
                if (getDirectory().getUri() == null)
-                       throw new IllegalStateException("Cannot save LDIF user admin: no URI is set");
+                       return; // ignore
                if (getDirectory().isReadOnly())
                        throw new IllegalStateException(
                                        "Cannot save LDIF user admin: " + getDirectory().getUri() + " is read-only");
@@ -123,10 +78,6 @@ public class LdifDao extends AbstractLdapDirectoryDao {
                        LdifWriter ldifWriter = new LdifWriter(out);
                        for (LdapName name : hierarchy.keySet())
                                ldifWriter.writeEntry(name, hierarchy.get(name).getAttributes());
-//                     for (LdapName name : groups.keySet())
-//                             ldifWriter.writeEntry(name, groups.get(name).getAttributes());
-//                     for (LdapName name : users.keySet())
-//                             ldifWriter.writeEntry(name, users.get(name).getAttributes());
                        for (LdapName name : entries.keySet())
                                ldifWriter.writeEntry(name, entries.get(name).getAttributes());
                } finally {
@@ -136,8 +87,6 @@ public class LdifDao extends AbstractLdapDirectoryDao {
 
        public void load(InputStream in) {
                try {
-//                     users.clear();
-//                     groups.clear();
                        entries.clear();
                        hierarchy.clear();
 
@@ -167,14 +116,7 @@ public class LdifDao extends AbstractLdapDirectoryDao {
                                        } else if (objectClass.toLowerCase().equals(getDirectory().getGroupObjectClass().toLowerCase())) {
                                                entries.put(key, newGroup(key, attributes));
                                                break objectClasses;
-//                                     } else if (objectClass.equalsIgnoreCase(LdapObjs.organization.name())) {
-//                                             // we only consider organizations which are not groups
-//                                             hierarchy.put(key, new LdifHierarchyUnit(this, key, HierarchyUnit.ORGANIZATION, attributes));
-//                                             break objectClasses;
                                        } else if (objectClass.equalsIgnoreCase(LdapObjs.organizationalUnit.name())) {
-//                                             String name = key.getRdn(key.size() - 1).toStrindirectoryDaog();
-//                                             if (getUserBase().equalsIgnoreCase(name) || getGroupBase().equalsIgnoreCase(name))
-//                                                     break objectClasses; // skip
                                                // TODO skip if it does not contain groups or users
                                                hierarchy.put(key, new LdapHierarchyUnit(getDirectory(), key, attributes));
                                                break objectClasses;
@@ -182,19 +124,6 @@ public class LdifDao extends AbstractLdapDirectoryDao {
                                }
                        }
 
-                       // link hierarchy
-//                     hierachyUnits: for (LdapName dn : hierarchy.keySet()) {
-//                             LdifHierarchyUnit unit = hierarchy.get(dn);
-//                             LdapName parentDn = (LdapName) dn.getPrefix(dn.size() - 1);
-//                             LdifHierarchyUnit parent = hierarchy.get(parentDn);
-//                             if (parent == null) {
-//                                     rootHierarchyUnits.add(unit);
-//                                     unit.parent = null;
-//                                     continue hierachyUnits;
-//                             }
-//                             parent.children.add(unit);
-//                             unit.parent = parent;
-//                     }
                } catch (NamingException | IOException e) {
                        throw new IllegalStateException("Cannot load user admin service from LDIF", e);
                }
@@ -215,10 +144,6 @@ public class LdifDao extends AbstractLdapDirectoryDao {
 
        @Override
        public LdapEntry doGetEntry(LdapName key) throws NameNotFoundException {
-//             if (groups.containsKey(key))
-//                     return groups.get(key);
-//             if (users.containsKey(key))
-//                     return users.get(key);
                if (entries.containsKey(key))
                        return entries.get(key);
                throw new NameNotFoundException(key + " not persisted");
@@ -243,12 +168,8 @@ public class LdifDao extends AbstractLdapDirectoryDao {
                Objects.requireNonNull(searchBase);
                ArrayList<LdapEntry> res = new ArrayList<>();
                if (f == null && deep && getDirectory().getBaseDn().equals(searchBase)) {
-//                     res.addAll(users.values());
-//                     res.addAll(groups.values());
                        res.addAll(entries.values());
                } else {
-//                     filterRoles(users, searchBase, f, deep, res);
-//                     filterRoles(groups, searchBase, f, deep, res);
                        filterRoles(entries, searchBase, f, deep, res);
                }
                return res;
@@ -309,26 +230,15 @@ public class LdifDao extends AbstractLdapDirectoryDao {
                for (LdapName dn : wc.getDeletedData().keySet()) {
                        if (entries.containsKey(dn))
                                entries.remove(dn);
-//                     if (users.containsKey(dn))
-//                             users.remove(dn);
-//                     else if (groups.containsKey(dn))
-//                             groups.remove(dn);
                        else
                                throw new IllegalStateException("User to delete not found " + dn);
                }
                // add
                for (LdapName dn : wc.getNewData().keySet()) {
                        LdapEntry user = (LdapEntry) wc.getNewData().get(dn);
-//                     if (users.containsKey(dn) || groups.containsKey(dn))
                        if (entries.containsKey(dn))
                                throw new IllegalStateException("User to create found " + dn);
                        entries.put(dn, user);
-//                     else if (Role.USER == user.getType())
-//                             users.put(dn, user);
-//                     else if (Role.GROUP == user.getType())
-//                             groups.put(dn, (DirectoryGroup) user);
-//                     else
-//                             throw new IllegalStateException("Unsupported role type " + user.getType() + " for new user " + dn);
                }
                // modify
                for (LdapName dn : wc.getModifiedData().keySet()) {
@@ -358,16 +268,6 @@ public class LdifDao extends AbstractLdapDirectoryDao {
        /*
         * HIERARCHY
         */
-
-//     @Override
-//     public int getHierarchyChildCount() {
-//             return rootHierarchyUnits.size();
-//     }
-//
-//     @Override
-//     public HierarchyUnit getHierarchyChild(int i) {
-//             return rootHierarchyUnits.get(i);
-//     }
        @Override
        public HierarchyUnit doGetHierarchyUnit(LdapName dn) {
                if (getDirectory().getBaseDn().equals(dn))
@@ -397,20 +297,4 @@ public class LdifDao extends AbstractLdapDirectoryDao {
        public void scope(LdifDao scoped) {
                scoped.entries = Collections.unmodifiableNavigableMap(entries);
        }
-
-//     @Override
-//     public Iterable<HierarchyUnit> getDirectHierarchyUnits(boolean functionalOnly) {
-//             if (functionalOnly) {
-//                     List<HierarchyUnit> res = new ArrayList<>();
-//                     for (HierarchyUnit hu : rootHierarchyUnits) {
-//                             if (hu.isFunctional())
-//                                     res.add(hu);
-//                     }
-//                     return res;
-//
-//             } else {
-//                     return rootHierarchyUnits;
-//             }
-//     }
-
 }