Java用 SSH クライアントライブラリ - ganymed-ssh2, sshj, JSch, Apache SSHD
主要な Java 用の SSH クライアントライブラリを使って簡単なサンプルを作成してみました。
ソースは http://github.com/fits/try_samples/tree/master/blog/20140814/
はじめに
Vagrant で実行中のゲスト OS に対して SSH で ls -al
を実行し、その結果を出力するだけの単純な処理を Groovy で実装してみる事にします。
今回の実装のポイントとなる点は下記のようなところだと思います。
- (1) Vagrant の秘密鍵ファイル
insecure_private_key
で認証 - (2) 未知のホスト鍵をチェックしないようにする (ssh における StrictHostKeyChecking=no と同等の処理)
Vagrant の秘密鍵ファイル insecure_private_key
をスクリプトファイルと同じディレクトリへコピーしておく事とします。
また、本件のサンプルコードではエラー処理や文字コード等を配慮していない点にご注意ください。
Ganymed SSH-2
元のオリジナルはかなり以前にメンテナンスが停止されていたり、Orion SSH や Trilead SSH のような同系統のライブラリが他にあったりと、どれを使えばよいのか分かり難い印象がありますが、とりあえず https://code.google.com/p/ganymed-ssh-2/ でメンテナンス継続されているものを使えば良さそうです。
ホスト鍵のチェックは connect
メソッドで制御できるようです。(チェックしたければ ServerHostKeyVerifier
を渡す)
ganymed_sample.groovy
@Grab('ch.ethz.ganymed:ganymed-ssh2:262') import ch.ethz.ssh2.Connection def con = new Connection('127.0.0.1', 2222) con.connect() // (1) Vagrant の秘密鍵ファイル insecure_private_key で認証 if (con.authenticateWithPublicKey('vagrant', new File('insecure_private_key'), null)) { def session = con.openSession() session.execCommand('ls -al') println session.stdout.text session.close() } con.close()
実行結果
> groovy ganymed_sample.groovy total 24 drwx------. 3 vagrant vagrant 4096 Aug 1 09:05 . drwxr-xr-x. 3 root root 20 Aug 1 08:36 .. -rw-------. 1 vagrant vagrant 202 Aug 10 05:28 .bash_history -rw-r--r--. 1 vagrant vagrant 18 Jun 10 00:31 .bash_logout -rw-r--r--. 1 vagrant vagrant 193 Jun 10 00:31 .bash_profile -rw-r--r--. 1 vagrant vagrant 231 Jun 10 00:31 .bashrc drwx------. 2 vagrant vagrant 28 Aug 1 09:05 .ssh -rw-------. 1 vagrant vagrant 644 Aug 1 09:05 .viminfo
sshj - SSHv2 library for Java
authPublickey
は connect
の後に実行する必要があります。
また、未知のホスト鍵をチェックしないようにするには、addHostKeyVerifier
で PromiscuousVerifier
を設定します。 (デフォルトではチェックするようになっています)
sshj_sample.groovy
@Grab('net.schmizz:sshj:0.10.0') @Grab('org.slf4j:slf4j-nop:1.7.7') import net.schmizz.sshj.SSHClient import net.schmizz.sshj.common.IOUtils import net.schmizz.sshj.transport.verification.PromiscuousVerifier def client = new SSHClient() // (2) 未知のホスト鍵をチェックしない client.addHostKeyVerifier(new PromiscuousVerifier()) client.connect('127.0.0.1', 2222) // (1) Vagrant の秘密鍵ファイル insecure_private_key で認証 client.authPublickey('vagrant', client.loadKeys('insecure_private_key')) def session = client.startSession() def cmd = session.exec('ls -al') println IOUtils.readFully(cmd.inputStream) session.close() client.disconnect()
実行結果
> groovy sshj_sample.groovy total 24 drwx------. 3 vagrant vagrant 4096 Aug 1 09:05 . drwxr-xr-x. 3 root root 20 Aug 1 08:36 .. -rw-------. 1 vagrant vagrant 202 Aug 10 05:28 .bash_history -rw-r--r--. 1 vagrant vagrant 18 Jun 10 00:31 .bash_logout -rw-r--r--. 1 vagrant vagrant 193 Jun 10 00:31 .bash_profile -rw-r--r--. 1 vagrant vagrant 231 Jun 10 00:31 .bashrc drwx------. 2 vagrant vagrant 28 Aug 1 09:05 .ssh -rw-------. 1 vagrant vagrant 644 Aug 1 09:05 .viminfo
JSch - Java Secure Channel
未知のホスト鍵をチェックしないようにするには setConfig
で StrictHostKeyChecking
を no
にします。
jsch_sample.groovy
@Grab('com.jcraft:jsch:0.1.51') import com.jcraft.jsch.JSch def jsch = new JSch() // (1) Vagrant の秘密鍵ファイル insecure_private_key で認証 jsch.addIdentity('insecure_private_key') // (2) 未知のホスト鍵をチェックしない jsch.setConfig('StrictHostKeyChecking', 'no') def session = jsch.getSession('vagrant', '127.0.0.1', 2222) session.connect() def ch = session.openChannel('exec') ch.setCommand('ls -al') ch.connect() println ch.inputStream.text ch.disconnect() session.disconnect()
実行結果
> groovy jsch_sample.groovy total 24 drwx------. 3 vagrant vagrant 4096 Aug 1 09:05 . drwxr-xr-x. 3 root root 20 Aug 1 08:36 .. -rw-------. 1 vagrant vagrant 202 Aug 10 05:28 .bash_history -rw-r--r--. 1 vagrant vagrant 18 Jun 10 00:31 .bash_logout -rw-r--r--. 1 vagrant vagrant 193 Jun 10 00:31 .bash_profile -rw-r--r--. 1 vagrant vagrant 231 Jun 10 00:31 .bashrc drwx------. 2 vagrant vagrant 28 Aug 1 09:05 .ssh -rw-------. 1 vagrant vagrant 644 Aug 1 09:05 .viminfo
Apache SSHD
Apache MINA をベースに SSH サーバーとクライアントの両方の API を備えたライブラリです。 他のライブラリと比べると多少面倒なように思います。
close
メソッドに false を指定すると graceful にクローズします。
sshd_sample.groovy
@Grab('org.apache.sshd:sshd-core:0.12.0') @Grab('org.apache.mina:mina-core:3.0.0-M2') @Grab('org.bouncycastle:bcpkix-jdk15on:1.51') @Grab('org.slf4j:slf4j-nop:1.7.7') import org.apache.sshd.ClientChannel import org.apache.sshd.SshClient import org.apache.sshd.common.keyprovider.FileKeyPairProvider def client = SshClient.setUpDefaultClient() client.start() def session = client.connect('vagrant', '127.0.0.1', 2222).await().getSession() // (1) Vagrant の秘密鍵ファイル insecure_private_key で認証 def keyProvider = new FileKeyPairProvider(['insecure_private_key'] as String[]) session.addPublicKeyIdentity(keyProvider.loadKeys().iterator().next()) def auth = session.auth() // verify の実行が必要 auth.verify() if (auth.isSuccess()) { def ch = session.createExecChannel('ls -al') def baos = new ByteArrayOutputStream() ch.setOut(baos) ch.open() // コマンド完了まで待機 ch.waitFor(ClientChannel.CLOSED, 0) ch.close(false) println baos.toString() } session.close(false) client.stop()
実行結果
> groovy sshd_sample.groovy total 24 drwx------. 3 vagrant vagrant 4096 Aug 1 09:05 . drwxr-xr-x. 3 root root 20 Aug 1 08:36 .. -rw-------. 1 vagrant vagrant 202 Aug 10 05:28 .bash_history -rw-r--r--. 1 vagrant vagrant 18 Jun 10 00:31 .bash_logout -rw-r--r--. 1 vagrant vagrant 193 Jun 10 00:31 .bash_profile -rw-r--r--. 1 vagrant vagrant 231 Jun 10 00:31 .bashrc drwx------. 2 vagrant vagrant 28 Aug 1 09:05 .ssh -rw-------. 1 vagrant vagrant 644 Aug 1 09:05 .viminfo