Improve SSH server. Rename node directory to private.
authorMathieu Baudier <mbaudier@argeo.org>
Thu, 21 Jul 2022 09:14:04 +0000 (11:14 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Thu, 21 Jul 2022 09:14:04 +0000 (11:14 +0200)
org.argeo.cms.lib.sshd/src/org/argeo/cms/ssh/CmsSshServer.java
org.argeo.cms/src/org/argeo/cms/CmsDeployProperty.java
org.argeo.cms/src/org/argeo/cms/CmsSshd.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/KernelConstants.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/PkiUtils.java
org.argeo.util/src/org/argeo/util/OS.java

index ab62654f23a32f521171904b42a394c278070317..f5609a37d5f70e2786153c567f96e0d0759a5684 100644 (file)
@@ -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<PosixFilePermission> 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;
        }
index ee3ec040da7a126cbee9fd96bc389ac41b40fb72..43343bfc75b41fdc73df58944371fd1bbd3f093a 100644 (file)
@@ -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
        //
index e38bf63131e5f79841d3be67baf145d7f1738a49..dd8621f0eb532ef6d6bea14494141c4b778e936c 100644 (file)
@@ -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";
 }
index fd2c5f9cdb47d4632ae7b9cf8464e92f3bdb94d9..902fe793b7a28ea98b377d65fb717c19d41f1274 100644 (file)
@@ -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<CmsDeployProperty, String> deployPropertyDefaults;
 
        public CmsStateImpl() {
+               this.deployPropertyDefaults = Collections.unmodifiableMap(createDeployPropertiesDefaults());
+       }
+
+       protected Map<CmsDeployProperty, String> createDeployPropertiesDefaults() {
                Map<CmsDeployProperty, String> 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<PosixFilePermission> 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())
index ab98c062585684c9a536dc95a20644d7208dc1bf..99e8fc0dc4c4440022a17f38465151b9bcbb9239 100644 (file)
@@ -88,7 +88,7 @@ public class CmsUserAdmin extends AggregatingUserAdmin {
 
        protected List<Dictionary<String, Object>> getUserDirectoryConfigs() {
                List<Dictionary<String, Object>> res = new ArrayList<>();
-               Path nodeBase = cmsState.getDataPath(KernelConstants.DIR_NODE);
+               Path nodeBase = cmsState.getDataPath(KernelConstants.DIR_PRIVATE);
                List<String> 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 {
index 1a1c076c23e4656bcd7fd4025d0c1d2fc46ad698..c80e86aea56fad68e155351dc2f4c8ec963ee27a 100644 (file)
@@ -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";
 }
index 5bf62e3aab9be2064282681f58fbc8a0e8485321..f47e544218456968cfeb7982031c9649589a3849 100644 (file)
@@ -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);
                }
index caf96dd8cd83a52394d6d67a1b4ea5bab74a1052..174f45b78841975c72f060cda91a7835a902347b 100644 (file)
@@ -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" };
        }