From: Mathieu Baudier Date: Thu, 21 Jul 2022 09:14:04 +0000 (+0200) Subject: Improve SSH server. Rename node directory to private. X-Git-Tag: v2.3.10~101 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=76a8481ee26616efa0fa59838a93bcad937b2692;p=lgpl%2Fargeo-commons.git Improve SSH server. Rename node directory to private. --- diff --git a/org.argeo.cms.lib.sshd/src/org/argeo/cms/ssh/CmsSshServer.java b/org.argeo.cms.lib.sshd/src/org/argeo/cms/ssh/CmsSshServer.java index ab62654f2..f5609a37d 100644 --- a/org.argeo.cms.lib.sshd/src/org/argeo/cms/ssh/CmsSshServer.java +++ b/org.argeo.cms.lib.sshd/src/org/argeo/cms/ssh/CmsSshServer.java @@ -1,16 +1,36 @@ package org.argeo.cms.ssh; import java.io.IOException; +import java.io.InputStream; +import java.io.Writer; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardOpenOption; +import java.nio.file.attribute.PosixFilePermission; +import java.security.KeyPair; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import org.apache.sshd.common.config.keys.PublicKeyEntry; import org.apache.sshd.common.forward.PortForwardingEventListener; +import org.apache.sshd.common.keyprovider.KeyPairProvider; import org.apache.sshd.common.session.Session; import org.apache.sshd.common.util.net.SshdSocketAddress; import org.apache.sshd.scp.server.ScpCommandFactory; import org.apache.sshd.server.SshServer; import org.apache.sshd.server.auth.gss.GSSAuthenticator; +import org.apache.sshd.server.config.keys.AuthorizedKeysAuthenticator; +import org.apache.sshd.server.config.keys.DefaultAuthorizedKeysAuthenticator; import org.apache.sshd.server.forward.AcceptAllForwardingFilter; import org.apache.sshd.server.jaas.JaasPasswordAuthenticator; import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider; @@ -25,7 +45,6 @@ import org.argeo.cms.CmsSshd; public class CmsSshServer implements CmsSshd { private final static CmsLog log = CmsLog.getLog(CmsSshServer.class); - private static final String DEFAULT_SSH_HOST_KEY_PATH = CmsConstants.NODE + '/' + CmsConstants.NODE + ".ser"; private CmsState cmsState; private SshServer sshd = null; @@ -41,30 +60,50 @@ public class CmsSshServer implements CmsSshd { host = cmsState.getDeployProperty(CmsDeployProperty.HOST.getProperty()); - Path hostKeyPath = cmsState.getDataPath(DEFAULT_SSH_HOST_KEY_PATH); + KeyPair nodeKeyPair = loadNodeKeyPair(); try { + // authorized keys + String authorizedKeysStr = cmsState.getDeployProperty(CmsDeployProperty.SSHD_AUTHORIZEDKEYS.getProperty()); + Path authorizedKeysPath = authorizedKeysStr != null ? Paths.get(authorizedKeysStr) + : AuthorizedKeysAuthenticator.getDefaultAuthorizedKeysFile(); + if (authorizedKeysStr != null && !Files.exists(authorizedKeysPath)) { + Files.createFile(authorizedKeysPath); + Set posixPermissions = new HashSet<>(); + posixPermissions.add(PosixFilePermission.OWNER_READ); + posixPermissions.add(PosixFilePermission.OWNER_WRITE); + Files.setPosixFilePermissions(authorizedKeysPath, posixPermissions); + + if (nodeKeyPair != null) + try { + String openSsshPublicKey = PublicKeyEntry.toString(nodeKeyPair.getPublic()); + try (Writer writer = Files.newBufferedWriter(authorizedKeysPath, StandardCharsets.US_ASCII, + StandardOpenOption.APPEND)) { + writer.write(openSsshPublicKey); + } + } catch (IOException e) { + log.error("Cannot add node public key to SSH authorized keys", e); + } + } + + // create server sshd = SshServer.setUpDefaultServer(); sshd.setPort(port); if (host != null) sshd.setHost(host); - if (hostKeyPath == null) - throw new IllegalStateException("An SSH server key must be set"); - sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(hostKeyPath)); - // sshd.setShellFactory(new ProcessShellFactory(new String[] { "/bin/sh", "-i", - // "-l" })); -// String[] shellCommand = OS.LOCAL.getDefaultShellCommand(); - // FIXME transfer args -// sshd.setShellFactory(new ProcessShellFactory(shellCommand)); - sshd.setShellFactory(InteractiveProcessShellFactory.INSTANCE); - sshd.setCommandFactory(new ScpCommandFactory()); + + // host key + if (nodeKeyPair != null) { + sshd.setKeyPairProvider(KeyPairProvider.wrap(nodeKeyPair)); + } else { + Path hostKeyPath = cmsState.getDataPath(DEFAULT_SSH_HOST_KEY_PATH); + if (hostKeyPath == null) // TODO deal with no data area? + throw new IllegalStateException("An SSH server key must be set"); + sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider(hostKeyPath)); + } // tunnels sshd.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE); - // sshd.setForwardingFilter(ForwardingFilter.asForwardingFilter(null, null, - // TcpForwardingFilter.DEFAULT)); - // sshd.setForwarderFactory(DefaultForwarderFactory.INSTANCE); -// TcpForwardingFilter tcpForwardingFilter = sshd.getTcpForwardingFilter(); sshd.addPortForwardingEventListener(new PortForwardingEventListener() { @Override @@ -94,22 +133,38 @@ public class CmsSshServer implements CmsSshd { }); // Authentication - // sshd.setPublickeyAuthenticator(new DefaultAuthorizedKeysAuthenticator(true)); - sshd.setPublickeyAuthenticator(null); + // FIXME use strict, set proper permissions, etc. + sshd.setPublickeyAuthenticator( + new DefaultAuthorizedKeysAuthenticator("user.name", authorizedKeysPath, true)); + // sshd.setPublickeyAuthenticator(null); // sshd.setKeyboardInteractiveAuthenticator(null); JaasPasswordAuthenticator jaasPasswordAuthenticator = new JaasPasswordAuthenticator(); jaasPasswordAuthenticator.setDomain(CmsAuth.NODE.getLoginContextName()); sshd.setPasswordAuthenticator(jaasPasswordAuthenticator); - Path krb5keyTab = cmsState.getDataPath("node/krb5.keytab"); - if (Files.exists(krb5keyTab)) { - // FIXME experimental - GSSAuthenticator gssAuthenticator = new GSSAuthenticator(); - gssAuthenticator.setKeytabFile(cmsState.getDataPath("node/krb5.keytab").toString()); - gssAuthenticator.setServicePrincipalName("HTTP@" + host); - sshd.setGSSAuthenticator(gssAuthenticator); + boolean gssApi = false; + if (gssApi) { + Path krb5keyTab = cmsState.getDataPath("private/krb5.keytab"); + if (Files.exists(krb5keyTab)) { + // FIXME experimental + GSSAuthenticator gssAuthenticator = new GSSAuthenticator(); + gssAuthenticator.setKeytabFile(krb5keyTab.toString()); + gssAuthenticator.setServicePrincipalName("HTTP@" + host); + sshd.setGSSAuthenticator(gssAuthenticator); + } } + // shell + // TODO make it configurable + sshd.setShellFactory(InteractiveProcessShellFactory.INSTANCE); +// String[] shellCommand = OS.LOCAL.getDefaultShellCommand(); +// StringJoiner command = new StringJoiner(" "); +// for (String str : shellCommand) { +// command.add(str); +// } +// sshd.setShellFactory(new ProcessShellFactory(command.toString(), shellCommand)); + sshd.setCommandFactory(new ScpCommandFactory()); + // SFTP sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory())); @@ -135,6 +190,27 @@ public class CmsSshServer implements CmsSshd { } + protected KeyPair loadNodeKeyPair() { + try { + char[] keyStorePassword = cmsState.getDeployProperty(CmsDeployProperty.SSL_PASSWORD.getProperty()) + .toCharArray(); + Path keyStorePath = Paths.get(cmsState.getDeployProperty(CmsDeployProperty.SSL_KEYSTORE.getProperty())); + String keyStoreType = cmsState.getDeployProperty(CmsDeployProperty.SSL_KEYSTORETYPE.getProperty()); + + KeyStore store = KeyStore.getInstance(keyStoreType, "SunJSSE"); + try (InputStream fis = Files.newInputStream(keyStorePath)) { + store.load(fis, keyStorePassword); + } + return new KeyPair(store.getCertificate(CmsConstants.NODE).getPublicKey(), + (PrivateKey) store.getKey(CmsConstants.NODE, keyStorePassword)); + } catch (IOException | KeyStoreException | NoSuchProviderException | NoSuchAlgorithmException + | CertificateException | IllegalArgumentException | UnrecoverableKeyException e) { + log.error("Cannot add node public key to SSH authorized keys", e); + return null; + } + + } + public void setCmsState(CmsState cmsState) { this.cmsState = cmsState; } diff --git a/org.argeo.cms/src/org/argeo/cms/CmsDeployProperty.java b/org.argeo.cms/src/org/argeo/cms/CmsDeployProperty.java index ee3ec040d..43343bfc7 100644 --- a/org.argeo.cms/src/org/argeo/cms/CmsDeployProperty.java +++ b/org.argeo.cms/src/org/argeo/cms/CmsDeployProperty.java @@ -71,6 +71,8 @@ public enum CmsDeployProperty { // /** Request an HTTP server on this port. */ SSHD_PORT("argeo.sshd.port"), + /** Path to admin authorized keys file. */ + SSHD_AUTHORIZEDKEYS("argeo.sshd.authorizedkeys"), // // INTERNATIONALIZATION // diff --git a/org.argeo.cms/src/org/argeo/cms/CmsSshd.java b/org.argeo.cms/src/org/argeo/cms/CmsSshd.java index e38bf6313..dd8621f0e 100644 --- a/org.argeo.cms/src/org/argeo/cms/CmsSshd.java +++ b/org.argeo.cms/src/org/argeo/cms/CmsSshd.java @@ -1,6 +1,10 @@ package org.argeo.cms; -/** Just a marker interface for the time being.*/ -public interface CmsSshd { +import org.argeo.api.cms.CmsConstants; +import org.argeo.cms.internal.runtime.KernelConstants; +/** Just a marker interface for the time being. */ +public interface CmsSshd { + final static String NODE_USERNAME_ALIAS = "user.name"; + final static String DEFAULT_SSH_HOST_KEY_PATH = KernelConstants.DIR_PRIVATE + '/' + CmsConstants.NODE + ".ser"; } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java index fd2c5f9cd..902fe793b 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java @@ -7,15 +7,18 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.nio.file.attribute.PosixFilePermission; import java.security.KeyStore; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.Set; import java.util.StringJoiner; import java.util.UUID; @@ -47,6 +50,10 @@ public class CmsStateImpl implements CmsState { private final Map deployPropertyDefaults; public CmsStateImpl() { + this.deployPropertyDefaults = Collections.unmodifiableMap(createDeployPropertiesDefaults()); + } + + protected Map createDeployPropertiesDefaults() { Map deployPropertyDefaults = new HashMap<>(); deployPropertyDefaults.put(CmsDeployProperty.NODE_INIT, "../../init"); deployPropertyDefaults.put(CmsDeployProperty.LOCALE, Locale.getDefault().toString()); @@ -66,7 +73,13 @@ public class CmsStateImpl implements CmsState { deployPropertyDefaults.put(CmsDeployProperty.SSL_TRUSTSTORETYPE, PkiUtils.PKCS12); deployPropertyDefaults.put(CmsDeployProperty.SSL_TRUSTSTOREPASSWORD, PkiUtils.DEFAULT_KEYSTORE_PASSWORD); - this.deployPropertyDefaults = Collections.unmodifiableMap(deployPropertyDefaults); + // SSH + Path authorizedKeysPath = getDataPath(KernelConstants.NODE_SSHD_AUTHORIZED_KEYS_PATH); + if (authorizedKeysPath != null) { + deployPropertyDefaults.put(CmsDeployProperty.SSHD_AUTHORIZEDKEYS, + authorizedKeysPath.toAbsolutePath().toString()); + } + return deployPropertyDefaults; } public void start() { @@ -112,7 +125,7 @@ public class CmsStateImpl implements CmsState { log.debug("## CMS starting... (" + uuid + ")\n" + sb + "\n"); } - Path nodeBase = getDataPath(CmsConstants.NODE); + Path nodeBase = getDataPath(KernelConstants.DIR_PRIVATE); if (nodeBase != null && !Files.exists(nodeBase)) {// first init firstInit(); } @@ -123,6 +136,21 @@ public class CmsStateImpl implements CmsState { } private void initSecurity() { + // private directory permissions + Path privateDir = KernelUtils.getOsgiInstancePath(KernelConstants.DIR_PRIVATE); + if (privateDir != null) { + // TODO rather check whether we can read and write + Set posixPermissions = new HashSet<>(); + posixPermissions.add(PosixFilePermission.OWNER_READ); + posixPermissions.add(PosixFilePermission.OWNER_WRITE); + posixPermissions.add(PosixFilePermission.OWNER_EXECUTE); + try { + Files.setPosixFilePermissions(privateDir, posixPermissions); + } catch (IOException e) { + log.error("Cannot set permissions on " + privateDir); + } + } + if (getDeployProperty(CmsDeployProperty.JAVA_LOGIN_CONFIG) == null) { String jaasConfig = KernelConstants.JAAS_CONFIG; URL url = getClass().getResource(jaasConfig); @@ -154,7 +182,7 @@ public class CmsStateImpl implements CmsState { getDeployProperty(CmsDeployProperty.SSL_KEYSTORETYPE)); try (Reader key = Files.newBufferedReader(pemKeyPath, StandardCharsets.US_ASCII); Reader cert = Files.newBufferedReader(pemCertPath, StandardCharsets.US_ASCII);) { - PkiUtils.loadPem(keyStore, key, keyStorePassword, cert); + PkiUtils.loadPrivateCertificatePem(keyStore, CmsConstants.NODE, key, keyStorePassword, cert); Files.createDirectories(keyStorePath.getParent()); PkiUtils.saveKeyStore(keyStorePath, keyStorePassword, keyStore); if (log.isDebugEnabled()) @@ -174,7 +202,7 @@ public class CmsStateImpl implements CmsState { KeyStore trustStore = PkiUtils.getKeyStore(trustStorePath, trustStorePassword, getDeployProperty(CmsDeployProperty.SSL_TRUSTSTORETYPE)); try (Reader cert = Files.newBufferedReader(ipaCaCertPath, StandardCharsets.US_ASCII);) { - PkiUtils.loadPem(trustStore, null, trustStorePassword, cert); + PkiUtils.loadTrustedCertificatePem(trustStore, trustStorePassword, cert); Files.createDirectories(keyStorePath.getParent()); PkiUtils.saveKeyStore(trustStorePath, trustStorePassword, trustStore); if (log.isDebugEnabled()) diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java index ab98c0625..99e8fc0dc 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsUserAdmin.java @@ -88,7 +88,7 @@ public class CmsUserAdmin extends AggregatingUserAdmin { protected List> getUserDirectoryConfigs() { List> res = new ArrayList<>(); - Path nodeBase = cmsState.getDataPath(KernelConstants.DIR_NODE); + Path nodeBase = cmsState.getDataPath(KernelConstants.DIR_PRIVATE); List uris = new ArrayList<>(); // node roles @@ -191,7 +191,7 @@ public class CmsUserAdmin extends AggregatingUserAdmin { try { if (uri == null) { String baseDn = (String) properties.get(DirectoryConf.baseDn.name()); - u = KernelUtils.getOsgiInstanceUri(KernelConstants.DIR_NODE + '/' + baseDn + ".ldif"); + u = KernelUtils.getOsgiInstanceUri(KernelConstants.DIR_PRIVATE + '/' + baseDn + ".ldif"); } else if (realm != null) { u = null; } else { diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/KernelConstants.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/KernelConstants.java index 1a1c076c2..c80e86aea 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/runtime/KernelConstants.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/runtime/KernelConstants.java @@ -1,46 +1,22 @@ package org.argeo.cms.internal.runtime; /** Internal CMS constants. */ -interface KernelConstants { +public interface KernelConstants { // Directories - String DIR_NODE = "node"; -// String DIR_REPOS = "repos"; -// String DIR_INDEXES = "indexes"; -// String DIR_TRANSACTIONS = "transactions"; + String DIR_PRIVATE = "private"; // Files -// String DEPLOY_CONFIG_PATH = DIR_NODE + '/' + CmsConstants.DEPLOY_BASEDN + ".ldif"; - String NODE_KEY_TAB_PATH = DIR_NODE + "/krb5.keytab"; + String NODE_KEY_TAB_PATH = DIR_PRIVATE + "/krb5.keytab"; + String NODE_SSHD_AUTHORIZED_KEYS_PATH = DIR_PRIVATE + "/authorized_keys"; // Security String JAAS_CONFIG = "/org/argeo/cms/internal/runtime/jaas.cfg"; String JAAS_CONFIG_IPA = "/org/argeo/cms/internal/runtime/jaas-ipa.cfg"; - // Java -// String JAAS_CONFIG_PROP = "java.security.auth.login.config"; - - // DEFAULTS JCR PATH -// String DEFAULT_HOME_BASE_PATH = "/home"; -// String DEFAULT_USERS_BASE_PATH = "/users"; -// String DEFAULT_GROUPS_BASE_PATH = "/groups"; - // KERBEROS String DEFAULT_KERBEROS_SERVICE = "HTTP"; // HTTP client - String COOKIE_POLICY_BROWSER_COMPATIBILITY = "compatibility"; - - // RWT / RAP - // String PATH_WORKBENCH = "/ui"; - // String PATH_WORKBENCH_PUBLIC = PATH_WORKBENCH + "/public"; - -// String JETTY_FACTORY_PID = "org.eclipse.equinox.http.jetty.config"; -// String JETTY_FACTORY_PID = "org.argeo.equinox.jetty.config"; - // default Jetty server configured via JettyConfigurator -// String DEFAULT_JETTY_SERVER = "default"; -// String CMS_JETTY_CUSTOMIZER_CLASS = "org.argeo.equinox.jetty.CmsJettyCustomizer"; + // String COOKIE_POLICY_BROWSER_COMPATIBILITY = "compatibility"; - // avoid dependencies -// String JACKRABBIT_REPOSITORY_URI = "org.apache.jackrabbit.repository.uri"; -// String JACKRABBIT_REMOTE_DEFAULT_WORKSPACE = "org.apache.jackrabbit.spi2davex.WorkspaceNameDefault"; } diff --git a/org.argeo.cms/src/org/argeo/cms/internal/runtime/PkiUtils.java b/org.argeo.cms/src/org/argeo/cms/internal/runtime/PkiUtils.java index 5bf62e3aa..f47e54421 100644 --- a/org.argeo.cms/src/org/argeo/cms/internal/runtime/PkiUtils.java +++ b/org.argeo.cms/src/org/argeo/cms/internal/runtime/PkiUtils.java @@ -22,6 +22,7 @@ import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Date; +import java.util.Objects; import javax.security.auth.x500.X500Principal; @@ -53,19 +54,20 @@ class PkiUtils { final static String PKCS12 = "PKCS12"; final static String JKS = "JKS"; - static final String DEFAULT_KEYSTORE_PATH = KernelConstants.DIR_NODE + '/' + CmsConstants.NODE + ".p12"; + static final String DEFAULT_KEYSTORE_PATH = KernelConstants.DIR_PRIVATE + '/' + CmsConstants.NODE + ".p12"; - static final String DEFAULT_TRUSTSTORE_PATH = KernelConstants.DIR_NODE + "/trusted.p12"; + static final String DEFAULT_TRUSTSTORE_PATH = KernelConstants.DIR_PRIVATE + "/trusted.p12"; - static final String DEFAULT_PEM_KEY_PATH = KernelConstants.DIR_NODE + '/' + CmsConstants.NODE + ".key"; + static final String DEFAULT_PEM_KEY_PATH = KernelConstants.DIR_PRIVATE + '/' + CmsConstants.NODE + ".key"; - static final String DEFAULT_PEM_CERT_PATH = KernelConstants.DIR_NODE + '/' + CmsConstants.NODE + ".crt"; + static final String DEFAULT_PEM_CERT_PATH = KernelConstants.DIR_PRIVATE + '/' + CmsConstants.NODE + ".crt"; static final String IPA_PEM_CA_CERT_PATH = "/etc/ipa/ca.crt"; static final String DEFAULT_KEYSTORE_PASSWORD = "changeit"; private final static String SUN_SECURITY_PROVIDER; + private final static String SUN_JSSE_SECURITY_PROVIDER; private final static String BC_SECURITY_PROVIDER; static { Security.addProvider(new BouncyCastleProvider()); @@ -73,6 +75,7 @@ class PkiUtils { // TODO report it BC_SECURITY_PROVIDER = "BC"; SUN_SECURITY_PROVIDER = "SUN"; + SUN_JSSE_SECURITY_PROVIDER = "SunJSSE"; } public static X509Certificate generateSelfSignedCertificate(KeyStore keyStore, X500Principal x500Principal, @@ -102,7 +105,7 @@ class PkiUtils { public static KeyStore getKeyStore(Path keyStoreFile, char[] keyStorePassword, String keyStoreType) { try { - KeyStore store = KeyStore.getInstance(keyStoreType, "SunJSSE"); + KeyStore store = KeyStore.getInstance(keyStoreType, SUN_JSSE_SECURITY_PROVIDER); if (Files.exists(keyStoreFile)) { try (InputStream fis = Files.newInputStream(keyStoreFile)) { store.load(fis, keyStorePassword); @@ -162,17 +165,24 @@ class PkiUtils { // return bos.toByteArray(); // } - public static void loadPem(KeyStore keyStore, Reader key, char[] keyPassword, Reader cert) { + public static void loadPrivateCertificatePem(KeyStore keyStore, String alias, Reader key, char[] keyPassword, + Reader cert) { + Objects.requireNonNull(keyStore); + Objects.requireNonNull(key); try { X509Certificate certificate = loadPemCertificate(cert); - if (key != null) { - PrivateKey privateKey = loadPemPrivateKey(key, keyPassword); - keyStore.setKeyEntry(certificate.getSubjectX500Principal().getName(), privateKey, keyPassword, - new java.security.cert.Certificate[] { certificate }); - } else { - TrustedCertificateEntry trustedCertificateEntry = new TrustedCertificateEntry(certificate); - keyStore.setEntry(certificate.getSubjectX500Principal().getName(), trustedCertificateEntry, null); - } + PrivateKey privateKey = loadPemPrivateKey(key, keyPassword); + keyStore.setKeyEntry(alias, privateKey, keyPassword, new java.security.cert.Certificate[] { certificate }); + } catch (KeyStoreException e) { + throw new RuntimeException("Cannot store PEM certificate", e); + } + } + + public static void loadTrustedCertificatePem(KeyStore keyStore,char[] keyStorePassword, Reader cert) { + try { + X509Certificate certificate = loadPemCertificate(cert); + TrustedCertificateEntry trustedCertificateEntry = new TrustedCertificateEntry(certificate); + keyStore.setEntry(certificate.getSubjectX500Principal().getName(), trustedCertificateEntry, null); } catch (KeyStoreException e) { throw new RuntimeException("Cannot store PEM certificate", e); } diff --git a/org.argeo.util/src/org/argeo/util/OS.java b/org.argeo.util/src/org/argeo/util/OS.java index caf96dd8c..174f45b78 100644 --- a/org.argeo.util/src/org/argeo/util/OS.java +++ b/org.argeo.util/src/org/argeo/util/OS.java @@ -36,7 +36,7 @@ public class OS { public String[] getDefaultShellCommand() { if (!isMSWindows()) - return new String[] { "/bin/sh", "-l", "-i" }; + return new String[] { "/bin/bash", "-l", "-i" }; else return new String[] { "cmd.exe", "/C" }; }