X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Finternal%2Fkernel%2FInitUtils.java;h=a2006a7049e306018c57902fb86c636e417fc904;hb=b71546ddc74d6ca49d252806aafd491c75dfe1fb;hp=ebb2ef8f7f3934f8652bde4ee3ac9d938d7dd534;hpb=581f2d67cac937fcbcd11c7af0c7256499b7195a;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/internal/kernel/InitUtils.java b/org.argeo.cms/src/org/argeo/cms/internal/kernel/InitUtils.java index ebb2ef8f7..a2006a704 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/kernel/InitUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/kernel/InitUtils.java @@ -5,8 +5,10 @@ import static org.argeo.cms.internal.kernel.KernelUtils.getFrameworkProp; import java.io.File; import java.io.FileFilter; import java.io.IOException; +import java.io.Reader; import java.net.InetAddress; import java.net.URI; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.security.KeyStore; @@ -19,12 +21,9 @@ import java.util.List; import javax.security.auth.x500.X500Principal; 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.internal.http.HttpConstants; -import org.argeo.cms.internal.jcr.RepoConf; -import org.argeo.node.NodeConstants; +import org.argeo.api.cms.CmsConstants; +import org.argeo.api.cms.CmsLog; +import org.argeo.cms.internal.http.InternalHttpConstants; import org.argeo.osgi.useradmin.UserAdminConf; /** @@ -32,82 +31,93 @@ import org.argeo.osgi.useradmin.UserAdminConf; * configuration. */ class InitUtils { - private final static Log log = LogFactory.getLog(InitUtils.class); + private final static CmsLog log = CmsLog.getLog(InitUtils.class); - /** Override the provided config with the framework properties */ - static Dictionary getNodeRepositoryConfig(Dictionary provided) { - Dictionary props = provided != null ? provided : new Hashtable(); - for (RepoConf repoConf : RepoConf.values()) { - Object value = getFrameworkProp(NodeConstants.NODE_REPO_PROP_PREFIX + repoConf.name()); - if (value != null) - props.put(repoConf.name(), value); - } - props.put(NodeConstants.CN, NodeConstants.NODE); - return props; - } - - static Dictionary getRepositoryConfig(String dataModelName, Dictionary provided) { - if (dataModelName.equals(NodeConstants.NODE) || dataModelName.equals(NodeConstants.HOME)) - throw new IllegalArgumentException("Data model '" + dataModelName + "' is reserved."); - Dictionary props = provided != null ? provided : new Hashtable(); - for (RepoConf repoConf : RepoConf.values()) { - Object value = getFrameworkProp( - NodeConstants.NODE_REPOS_PROP_PREFIX + dataModelName + '.' + repoConf.name()); - if (value != null) - props.put(repoConf.name(), value); - } - if (props.size() != 0) - props.put(NodeConstants.CN, dataModelName); - return props; - } /** Override the provided config with the framework properties */ static Dictionary getHttpServerConfig(Dictionary provided) { String httpPort = getFrameworkProp("org.osgi.service.http.port"); String httpsPort = getFrameworkProp("org.osgi.service.http.port.secure"); /// TODO make it more generic - String httpHost = getFrameworkProp(HttpConstants.JETTY_PROPERTY_PREFIX + HttpConstants.HTTP_HOST); - String httpsHost = getFrameworkProp(HttpConstants.JETTY_PROPERTY_PREFIX + HttpConstants.HTTPS_HOST); + String httpHost = getFrameworkProp( + InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.HTTP_HOST); + String httpsHost = getFrameworkProp( + InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.HTTPS_HOST); String webSocketEnabled = getFrameworkProp( - HttpConstants.JETTY_PROPERTY_PREFIX + HttpConstants.WEB_SOCKET_ENABLED); + InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.WEBSOCKET_ENABLED); final Hashtable props = new Hashtable(); // try { if (httpPort != null || httpsPort != null) { - if (httpPort != null) { - props.put(HttpConstants.HTTP_PORT, httpPort); - props.put(HttpConstants.HTTP_ENABLED, true); + boolean httpEnabled = httpPort != null; + props.put(InternalHttpConstants.HTTP_ENABLED, httpEnabled); + boolean httpsEnabled = httpsPort != null; + props.put(InternalHttpConstants.HTTPS_ENABLED, httpsEnabled); + + if (httpEnabled) { + props.put(InternalHttpConstants.HTTP_PORT, httpPort); + if (httpHost != null) + props.put(InternalHttpConstants.HTTP_HOST, httpHost); } - if (httpsPort != null) { - props.put(HttpConstants.HTTPS_PORT, httpsPort); - props.put(HttpConstants.HTTPS_ENABLED, true); + + if (httpsEnabled) { + props.put(InternalHttpConstants.HTTPS_PORT, httpsPort); + if (httpsHost != null) + props.put(InternalHttpConstants.HTTPS_HOST, httpsHost); + + // server certificate Path keyStorePath = KernelUtils.getOsgiInstancePath(KernelConstants.DEFAULT_KEYSTORE_PATH); - String keyStorePassword = getFrameworkProp( - HttpConstants.JETTY_PROPERTY_PREFIX + HttpConstants.SSL_PASSWORD); - if (keyStorePassword == null) - keyStorePassword = "changeit"; + Path pemKeyPath = KernelUtils.getOsgiInstancePath(KernelConstants.DEFAULT_PEM_KEY_PATH); + Path pemCertPath = KernelUtils.getOsgiInstancePath(KernelConstants.DEFAULT_PEM_CERT_PATH); + String keyStorePasswordStr = getFrameworkProp( + InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.SSL_PASSWORD); + char[] keyStorePassword; + if (keyStorePasswordStr == null) + keyStorePassword = "changeit".toCharArray(); + else + keyStorePassword = keyStorePasswordStr.toCharArray(); + + // if PEM files both exists, update the PKCS12 file + if (Files.exists(pemCertPath) && Files.exists(pemKeyPath)) { + // TODO check certificate update time? monitor changes? + KeyStore keyStore = PkiUtils.getKeyStore(keyStorePath, keyStorePassword, PkiUtils.PKCS12); + try (Reader key = Files.newBufferedReader(pemKeyPath, StandardCharsets.US_ASCII); + Reader cert = Files.newBufferedReader(pemCertPath, StandardCharsets.US_ASCII);) { + PkiUtils.loadPem(keyStore, key, keyStorePassword, cert); + PkiUtils.saveKeyStore(keyStorePath, keyStorePassword, keyStore); + if (log.isDebugEnabled()) + log.debug("PEM certificate stored in " + keyStorePath); + } catch (IOException e) { + log.error("Cannot read PEM files " + pemKeyPath + " and " + pemCertPath, e); + } + } + if (!Files.exists(keyStorePath)) - createSelfSignedKeyStore(keyStorePath, keyStorePassword); - props.put(HttpConstants.SSL_KEYSTORETYPE, "PKCS12"); - props.put(HttpConstants.SSL_KEYSTORE, keyStorePath.toString()); - props.put(HttpConstants.SSL_PASSWORD, keyStorePassword); - props.put(HttpConstants.SSL_WANTCLIENTAUTH, true); + createSelfSignedKeyStore(keyStorePath, keyStorePassword, PkiUtils.PKCS12); + props.put(InternalHttpConstants.SSL_KEYSTORETYPE, PkiUtils.PKCS12); + props.put(InternalHttpConstants.SSL_KEYSTORE, keyStorePath.toString()); + props.put(InternalHttpConstants.SSL_PASSWORD, new String(keyStorePassword)); + +// props.put(InternalHttpConstants.SSL_KEYSTORETYPE, "PKCS11"); +// props.put(InternalHttpConstants.SSL_KEYSTORE, "../../nssdb"); +// props.put(InternalHttpConstants.SSL_PASSWORD, keyStorePassword); + + // client certificate authentication + String wantClientAuth = getFrameworkProp( + InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.SSL_WANTCLIENTAUTH); + if (wantClientAuth != null) + props.put(InternalHttpConstants.SSL_WANTCLIENTAUTH, Boolean.parseBoolean(wantClientAuth)); String needClientAuth = getFrameworkProp( - HttpConstants.JETTY_PROPERTY_PREFIX + HttpConstants.SSL_NEEDCLIENTAUTH); - if (needClientAuth != null) { - props.put(HttpConstants.SSL_NEEDCLIENTAUTH, Boolean.parseBoolean(needClientAuth)); - } + InternalHttpConstants.JETTY_PROPERTY_PREFIX + InternalHttpConstants.SSL_NEEDCLIENTAUTH); + if (needClientAuth != null) + props.put(InternalHttpConstants.SSL_NEEDCLIENTAUTH, Boolean.parseBoolean(needClientAuth)); } - if (httpHost != null) - props.put(HttpConstants.HTTP_HOST, httpHost); - if (httpsHost != null) - props.put(HttpConstants.HTTPS_HOST, httpHost); - if (webSocketEnabled != null) - if (webSocketEnabled.equals("true")) - props.put(HttpConstants.WEB_SOCKET_ENABLED, true); + // web socket + if (webSocketEnabled != null && webSocketEnabled.equals("true")) + props.put(InternalHttpConstants.WEBSOCKET_ENABLED, true); - props.put(NodeConstants.CN, NodeConstants.DEFAULT); + props.put(CmsConstants.CN, CmsConstants.DEFAULT); } return props; } @@ -118,8 +128,8 @@ class InitUtils { List uris = new ArrayList<>(); // node roles - String nodeRolesUri = getFrameworkProp(NodeConstants.ROLES_URI); - String baseNodeRoleDn = NodeConstants.ROLES_BASEDN; + String nodeRolesUri = getFrameworkProp(CmsConstants.ROLES_URI); + String baseNodeRoleDn = CmsConstants.ROLES_BASEDN; if (nodeRolesUri == null) { nodeRolesUri = baseNodeRoleDn + ".ldif"; File nodeRolesFile = new File(nodeBaseDir, nodeRolesUri); @@ -128,31 +138,31 @@ class InitUtils { FileUtils.copyInputStreamToFile(InitUtils.class.getResourceAsStream(baseNodeRoleDn + ".ldif"), nodeRolesFile); } catch (IOException e) { - throw new CmsException("Cannot copy demo resource", e); + throw new RuntimeException("Cannot copy demo resource", e); } // nodeRolesUri = nodeRolesFile.toURI().toString(); } uris.add(nodeRolesUri); // node tokens - String nodeTokensUri = getFrameworkProp(NodeConstants.TOKENS_URI); - String baseNodeTokensDn = NodeConstants.TOKENS_BASEDN; + String nodeTokensUri = getFrameworkProp(CmsConstants.TOKENS_URI); + String baseNodeTokensDn = CmsConstants.TOKENS_BASEDN; if (nodeTokensUri == null) { nodeTokensUri = baseNodeTokensDn + ".ldif"; - File nodeRolesFile = new File(nodeBaseDir, nodeRolesUri); - if (!nodeRolesFile.exists()) + File nodeTokensFile = new File(nodeBaseDir, nodeTokensUri); + if (!nodeTokensFile.exists()) try { FileUtils.copyInputStreamToFile(InitUtils.class.getResourceAsStream(baseNodeTokensDn + ".ldif"), - nodeRolesFile); + nodeTokensFile); } catch (IOException e) { - throw new CmsException("Cannot copy demo resource", e); + throw new RuntimeException("Cannot copy demo resource", e); } // nodeRolesUri = nodeRolesFile.toURI().toString(); } uris.add(nodeTokensUri); // Business roles - String userAdminUris = getFrameworkProp(NodeConstants.USERADMIN_URIS); + String userAdminUris = getFrameworkProp(CmsConstants.USERADMIN_URIS); if (userAdminUris == null) { String demoBaseDn = "dc=example,dc=com"; userAdminUris = demoBaseDn + ".ldif"; @@ -166,7 +176,7 @@ class InitUtils { FileUtils.copyInputStreamToFile( InitUtils.class.getResourceAsStream("example-ou=roles,ou=node.ldif"), systemRolesFile); } catch (IOException e) { - throw new CmsException("Cannot copy demo resources", e); + throw new RuntimeException("Cannot copy demo resources", e); } // userAdminUris = businessRolesFile.toURI().toString(); log.warn("## DEV Using dummy base DN " + demoBaseDn); @@ -181,7 +191,8 @@ class InitUtils { try { u = new URI(uri); if (u.getPath() == null) - throw new CmsException("URI " + uri + " must have a path in order to determine base DN"); + throw new IllegalArgumentException( + "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(); @@ -189,12 +200,12 @@ class InitUtils { // u = KernelUtils.getOsgiInstanceUri(KernelConstants.DIR_NODE + '/' + uri); u = new URI(uri); } else - throw new CmsException("Cannot interpret " + uri + " as an uri"); + throw new IllegalArgumentException("Cannot interpret " + uri + " as an uri"); } else if (u.getScheme().equals(UserAdminConf.SCHEME_FILE)) { u = new File(u).getCanonicalFile().toURI(); } } catch (Exception e) { - throw new CmsException("Cannot interpret " + uri + " as an uri", e); + throw new RuntimeException("Cannot interpret " + uri + " as an uri", e); } Dictionary properties = UserAdminConf.uriAsProperties(u.toString()); res.add(properties); @@ -208,61 +219,69 @@ class InitUtils { * some files (typically LDIF, etc). */ static void prepareFirstInitInstanceArea() { - String nodeInit = getFrameworkProp(NodeConstants.NODE_INIT); - if (nodeInit == null) - nodeInit = "../../init"; - if (nodeInit.startsWith("http")) { - // remoteFirstInit(nodeInit); - return; - } + String nodeInits = getFrameworkProp(CmsConstants.NODE_INIT); + if (nodeInits == null) + nodeInits = "../../init"; - // TODO use java.nio.file - File initDir; - if (nodeInit.startsWith(".")) - initDir = KernelUtils.getExecutionDir(nodeInit); - else - initDir = new File(nodeInit); - // TODO also uncompress archives - if (initDir.exists()) - try { - FileUtils.copyDirectory(initDir, KernelUtils.getOsgiInstanceDir(), new FileFilter() { + for (String nodeInit : nodeInits.split(",")) { + + if (nodeInit.startsWith("http")) { + // TODO reconnect it + //registerRemoteInit(nodeInit); + } else { + + // TODO use java.nio.file + File initDir; + if (nodeInit.startsWith(".")) + initDir = KernelUtils.getExecutionDir(nodeInit); + else + initDir = new File(nodeInit); + // TODO also uncompress archives + if (initDir.exists()) + try { + FileUtils.copyDirectory(initDir, KernelUtils.getOsgiInstanceDir(), new FileFilter() { - @Override - public boolean accept(File pathname) { - if (pathname.getName().equals(".svn") || pathname.getName().equals(".git")) - return false; - return true; + @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); } - }); - log.info("CMS initialized from " + initDir.getCanonicalPath()); - } catch (IOException e) { - throw new CmsException("Cannot initialize from " + initDir, e); } + } } - private static void createSelfSignedKeyStore(Path keyStorePath, String keyStorePassword) { + private static void createSelfSignedKeyStore(Path keyStorePath, char[] keyStorePassword, String keyStoreType) { // for (Provider provider : Security.getProviders()) // System.out.println(provider.getName()); - File keyStoreFile = keyStorePath.toFile(); - char[] ksPwd = keyStorePassword.toCharArray(); - char[] keyPwd = Arrays.copyOf(ksPwd, ksPwd.length); - if (!keyStoreFile.exists()) { +// File keyStoreFile = keyStorePath.toFile(); + char[] keyPwd = Arrays.copyOf(keyStorePassword, keyStorePassword.length); + if (!Files.exists(keyStorePath)) { try { - keyStoreFile.getParentFile().mkdirs(); - KeyStore keyStore = PkiUtils.getKeyStore(keyStoreFile, ksPwd); + Files.createDirectories(keyStorePath.getParent()); + KeyStore keyStore = PkiUtils.getKeyStore(keyStorePath, keyStorePassword, keyStoreType); PkiUtils.generateSelfSignedCertificate(keyStore, new X500Principal("CN=" + InetAddress.getLocalHost().getHostName() + ",OU=UNSECURE,O=UNSECURE"), 1024, keyPwd); - PkiUtils.saveKeyStore(keyStoreFile, ksPwd, keyStore); + PkiUtils.saveKeyStore(keyStorePath, keyStorePassword, keyStore); if (log.isDebugEnabled()) - log.debug("Created self-signed unsecure keystore " + keyStoreFile); + log.debug("Created self-signed unsecure keystore " + keyStorePath); } catch (Exception e) { - if (keyStoreFile.length() == 0) - keyStoreFile.delete(); - log.error("Cannot create keystore " + keyStoreFile, e); + try { + if (Files.size(keyStorePath) == 0) + Files.delete(keyStorePath); + } catch (IOException e1) { + // silent + } + log.error("Cannot create keystore " + keyStorePath, e); } } else { - throw new CmsException("Keystore " + keyStorePath + " already exists"); + throw new IllegalStateException("Keystore " + keyStorePath + " already exists"); } }