Connessione SSH con Java

Java Top

Ho appena annunciato il nuovo corso Learn Spring , incentrato sui fondamenti di Spring 5 e Spring Boot 2:

>> SCOPRI IL CORSO

1. Introduzione

SSH, noto anche come Secure Shell o Secure Socket Shell, è un protocollo di rete che consente a un computer di connettersi in modo sicuro a un altro computer su una rete non protetta. In questo tutorial, mostreremo come stabilire una connessione a un server SSH remoto con Java utilizzando le librerie JSch e Apache MINA SSHD .

Nei nostri esempi, apriremo prima la connessione SSH, quindi eseguiremo un comando, leggeremo l'output e lo scriveremo sulla console e, infine, chiuderemo la connessione SSH. Manterremo il codice di esempio il più semplice possibile.

2. JSch

JSch è l'implementazione Java di SSH2 che ci consente di connetterci a un server SSH e utilizzare il port forwarding, X11 forwarding e il trasferimento di file. Inoltre, è concesso in licenza con la licenza in stile BSD e ci fornisce un modo semplice per stabilire una connessione SSH con Java.

Per prima cosa, aggiungiamo la dipendenza JSch Maven al nostro file pom.xml :

 com.jcraft jsch 0.1.55 

2.1. Implementazione

Per stabilire una connessione SSH utilizzando JSch, abbiamo bisogno di un nome utente, una password, un URL host e una porta SSH . La porta SSH predefinita è 22, ma potrebbe accadere che configureremo il server per utilizzare un'altra porta per le connessioni SSH:

public static void listFolderStructure(String username, String password, String host, int port, String command) throws Exception { Session session = null; ChannelExec channel = null; try { session = new JSch().getSession(username, host, port); session.setPassword(password); session.setConfig("StrictHostKeyChecking", "no"); session.connect(); channel = (ChannelExec) session.openChannel("exec"); channel.setCommand(command); ByteArrayOutputStream responseStream = new ByteArrayOutputStream(); channel.setOutputStream(responseStream); channel.connect(); while (channel.isConnected()) { Thread.sleep(100); } String responseString = new String(responseStream.toByteArray()); System.out.println(responseString); } finally { if (session != null) { session.disconnect(); } if (channel != null) { channel.disconnect(); } } }

Come possiamo vedere nel codice, creiamo prima una sessione client e la configuriamo per la connessione al nostro server SSH. Quindi, creiamo un canale client utilizzato per comunicare con il server SSH in cui forniamo un tipo di canale - in questo caso, exec, il che significa che passeremo i comandi della shell al server.

Inoltre, dovremmo impostare il flusso di output per il nostro canale in cui verrà scritta la risposta del server. Dopo aver stabilito la connessione utilizzando il metodo channel.connect () , il comando viene passato e la risposta ricevuta viene scritta sulla console.

Vediamo come utilizzare i diversi parametri di configurazione che JSch offre :

  • StrictHostKeyChecking : indica se l'applicazione controllerà se la chiave pubblica dell'host può essere trovata tra gli host noti. Inoltre, i valori dei parametri disponibili sono ask , yes e no , dove ask è l'impostazione predefinita. Se impostiamo questa proprietà su yes , JSch non aggiungerà mai automaticamente la chiave host al file known_hosts e si rifiuterà di connettersi agli host la cui chiave host è stata modificata. Ciò costringe l'utente ad aggiungere manualmente tutti i nuovi host. Se lo impostiamo su no , JSch aggiungerà automaticamente una nuova chiave host all'elenco degli host conosciuti
  • compressione.s2c : specifica se utilizzare la compressione per il flusso di dati dal server alla nostra applicazione client. I valori disponibili sono zlib e nessuno dove il secondo è il valore predefinito
  • compression.c2s : specifica se utilizzare la compressione per il flusso di dati nella direzione client-server. I valori disponibili sono zlib e nessuno dove il secondo è il valore predefinito

È importante chiudere la sessione e il canale SFTP al termine della comunicazione con il server per evitare perdite di memoria .

3. Apache MINA SSHD

Apache MINA SSHD fornisce il supporto SSH per le applicazioni basate su Java. Questa libreria è basata su Apache MINA, una libreria IO asincrona scalabile e ad alte prestazioni.

Aggiungiamo la dipendenza Apache Mina SSHD Maven:

 org.apache.sshd sshd-core 2.5.1 

3.1. Implementazione

Vediamo il codice di esempio per la connessione al server SSH utilizzando Apache MINA SSHD:

public static void listFolderStructure(String username, String password, String host, int port, long defaultTimeoutSeconds, String command) throws IOException { SshClient client = SshClient.setUpDefaultClient(); client.start(); try (ClientSession session = client.connect(username, host, port) .verify(defaultTimeoutSeconds, TimeUnit.SECONDS).getSession()) { session.addPasswordIdentity(password); session.auth().verify(defaultTimeoutSeconds, TimeUnit.SECONDS); try (ByteArrayOutputStream responseStream = new ByteArrayOutputStream(); ClientChannel channel = session.createChannel(Channel.CHANNEL_SHELL)) { channel.setOut(responseStream); try { channel.open().verify(defaultTimeoutSeconds, TimeUnit.SECONDS); try (OutputStream pipedIn = channel.getInvertedIn()) { pipedIn.write(command.getBytes()); pipedIn.flush(); } channel.waitFor(EnumSet.of(ClientChannelEvent.CLOSED), TimeUnit.SECONDS.toMillis(defaultTimeoutSeconds)); String responseString = new String(responseStream.toByteArray()); System.out.println(responseString); } finally { channel.close(false); } } } finally { client.stop(); } }

Quando si lavora con Apache MINA SSHD, abbiamo una sequenza di eventi abbastanza simile a quella di JSch. Innanzitutto, stabiliamo una connessione a un server SSH utilizzando l' istanza della classe SshClient . Se lo inizializziamo con SshClient.setupDefaultClient (), saremo in grado di lavorare con l'istanza che ha una configurazione predefinita adatta alla maggior parte dei casi d'uso. Ciò include cifrature, compressione, MAC, scambi di chiavi e firme.

Dopodiché, creeremo ClientChannel e gli collegheremo ByteArrayOutputStream , in modo da utilizzarlo come flusso di risposta. Come possiamo vedere, SSHD richiede timeout definiti per ogni operazione. Ci permette inoltre di definire quanto tempo attenderà la risposta del server dopo che il comando è stato passato utilizzando il metodo Channel.waitFor () .

È importante notare che SSHD scriverà l'output completo della console nel flusso di risposta. JSch lo farà solo con il risultato dell'esecuzione del comando.

La documentazione completa su Apache Mina SSHD è disponibile nel repository GitHub ufficiale del progetto.

4. Conclusione

Questo articolo ha illustrato come stabilire una connessione SSH con Java utilizzando due delle librerie Java disponibili: JSch e Apache Mina SSHD. Abbiamo anche mostrato come passare il comando al server remoto e ottenere il risultato dell'esecuzione. Inoltre, su GitHub sono disponibili esempi di codice completi.

Fondo Java

Ho appena annunciato il nuovo corso Learn Spring , incentrato sui fondamenti di Spring 5 e Spring Boot 2:

>> SCOPRI IL CORSO