Improve SSH layer
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 9 Jul 2022 08:30:32 +0000 (10:30 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 9 Jul 2022 08:30:32 +0000 (10:30 +0200)
org.argeo.cms.ssh/src/org/argeo/cms/ssh/AbstractSsh.java
org.argeo.cms.ssh/src/org/argeo/cms/ssh/SshKeyPair.java

index 2d195de9f3d0f4ce3e9644218d840abc6cdc1d02..f2525bff850b0c914709309f4389d0b2679a7671 100644 (file)
@@ -20,7 +20,7 @@ import org.apache.sshd.sftp.client.fs.SftpFileSystemProvider;
 import org.argeo.api.cms.CmsLog;
 
 @SuppressWarnings("restriction")
-abstract class AbstractSsh {
+public abstract class AbstractSsh {
        private final static CmsLog log = CmsLog.getLog(AbstractSsh.class);
 
        private static SshClient sshClient;
@@ -31,7 +31,7 @@ abstract class AbstractSsh {
 
        private SshKeyPair sshKeyPair;
 
-       synchronized SshClient getSshClient() {
+       public synchronized SshClient getSshClient() {
                if (sshClient == null) {
                        long begin = System.currentTimeMillis();
                        sshClient = SshClient.setUpDefaultClient();
@@ -51,33 +51,52 @@ abstract class AbstractSsh {
                return sftpFileSystemProvider;
        }
 
-       void authenticate() {
-               try {
-                       if (sshKeyPair != null) {
-                               session.addPublicKeyIdentity(sshKeyPair.asKeyPair());
-                       } else {
-
-                               if (!passwordSet) {
-                                       String password;
-                                       Console console = System.console();
-                                       if (console == null) {// IDE
-                                               System.out.print("Password: ");
-                                               try (Scanner s = new Scanner(System.in)) {
-                                                       password = s.next();
-                                               }
-                                       } else {
-                                               console.printf("Password: ");
-                                               char[] pwd = console.readPassword();
-                                               password = new String(pwd);
-                                               Arrays.fill(pwd, ' ');
+       public void authenticate() {
+               if (sshKeyPair != null) {
+                       session.addPublicKeyIdentity(sshKeyPair.asKeyPair());
+               } else {
+
+                       if (!passwordSet) {
+                               String password;
+                               Console console = System.console();
+                               if (console == null) {// IDE
+                                       System.out.print("Password: ");
+                                       try (Scanner s = new Scanner(System.in)) {
+                                               password = s.next();
                                        }
-                                       session.addPasswordIdentity(password);
-                                       passwordSet = true;
+                               } else {
+                                       console.printf("Password: ");
+                                       char[] pwd = console.readPassword();
+                                       password = new String(pwd);
+                                       Arrays.fill(pwd, ' ');
                                }
+                               session.addPasswordIdentity(password);
+                               passwordSet = true;
                        }
+               }
+               verifyAuth();
+       }
+
+       public void verifyAuth() {
+               try {
                        session.auth().verify(1000l);
                } catch (IOException e) {
-                       throw new IllegalStateException(e);
+                       throw new IllegalStateException("Cannot verify auth", e);
+               }
+       }
+
+       public static char[] readPassword() {
+               Console console = System.console();
+               if (console == null) {// IDE
+                       System.out.print("Password: ");
+                       try (Scanner s = new Scanner(System.in)) {
+                               String password = s.next();
+                               return password.toCharArray();
+                       }
+               } else {
+                       console.printf("Password: ");
+                       char[] pwd = console.readPassword();
+                       return pwd;
                }
        }
 
@@ -136,7 +155,7 @@ abstract class AbstractSsh {
                }
        }
 
-       void closeSession() {
+       public void closeSession() {
                if (session == null)
                        throw new IllegalStateException("No session is open");
                try {
@@ -156,6 +175,10 @@ abstract class AbstractSsh {
                this.sshKeyPair = sshKeyPair;
        }
 
+       public static void openShell(AbstractSsh ssh) {
+               openShell(ssh.getSession());
+       }
+
        public static void openShell(ClientSession session) {
                try (ClientChannel channel = session.createChannel(ClientChannel.CHANNEL_SHELL)) {
                        channel.setIn(new NoCloseInputStream(System.in));
index ed1818d407bca0838b0658f24212c1a0b59f219a..f5cbb04501498c725794edcce32f173ed79e4a87 100644 (file)
@@ -20,9 +20,12 @@ import java.security.spec.RSAPublicKeySpec;
 import org.apache.sshd.common.config.keys.KeyUtils;
 import org.apache.sshd.common.config.keys.PublicKeyEntry;
 import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import org.bouncycastle.openssl.PEMDecryptorProvider;
+import org.bouncycastle.openssl.PEMEncryptedKeyPair;
 import org.bouncycastle.openssl.PEMKeyPair;
 import org.bouncycastle.openssl.PEMParser;
 import org.bouncycastle.openssl.PKCS8Generator;
+import org.bouncycastle.openssl.bc.BcPEMDecryptorProvider;
 import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
 import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
 import org.bouncycastle.openssl.jcajce.JcaPKCS8Generator;
@@ -125,12 +128,32 @@ public class SshKeyPair {
                }
        }
 
+       public static SshKeyPair loadDefault(char[] password) {
+               Path privateKeyPath = Paths.get(System.getProperty("user.home") + "/.ssh/id_rsa");
+               // TODO try other formats
+               return load(privateKeyPath, password);
+       }
+
+       public static SshKeyPair load(Path privateKeyPath, char[] password) {
+               try (Reader reader = Files.newBufferedReader(privateKeyPath)) {
+                       return load(reader, password);
+               } catch (IOException e) {
+                       throw new IllegalStateException("Cannot load private key from " + privateKeyPath, e);
+               }
+
+       }
+
        public static SshKeyPair load(Reader reader, char[] password) {
                try (PEMParser pemParser = new PEMParser(reader)) {
                        Object object = pemParser.readObject();
                        JcaPEMKeyConverter converter = new JcaPEMKeyConverter();// .setProvider("BC");
                        KeyPair kp;
-                       if (object instanceof PKCS8EncryptedPrivateKeyInfo) {
+                       if (object instanceof PEMEncryptedKeyPair) {
+                               PEMEncryptedKeyPair ekp = (PEMEncryptedKeyPair) object;
+                               PEMDecryptorProvider decryptorProvider = new BcPEMDecryptorProvider(password);
+                               PEMKeyPair pemKp = ekp.decryptKeyPair(decryptorProvider);
+                               kp = converter.getKeyPair(pemKp);
+                       } else if (object instanceof PKCS8EncryptedPrivateKeyInfo) {
                                // Encrypted key - we will use provided password
                                PKCS8EncryptedPrivateKeyInfo ckp = (PKCS8EncryptedPrivateKeyInfo) object;
 //                             PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password);