2011年07月11日

JavaでSSHサーバを動かそう(Apache MINA/SSHD)

ふと、Javaだけで動くSSHサーバってあるんだろうか?と思い探してみたところApache MINAプロジェクトからSSHDとして提供されているのを見つけました。

15)


バージョンが0.5ですからまだベータ版といったところでしょうか。
早速使ってみましょう。

ダウンロードしたzipファイルを解凍し、libフォルダに含まれる以下のjarをクラス(ビルド)パスに含めます。

・mina-core-2.0.1.jar
・slf4j-api-1.4.3.jar
・slf4j-simple-1.4.3.jar
・sshd-core-0.5.0.jar
・sshd-pam-0.5.0.jar

 次にSSHサーバのサンプルコードです。

  SshServer sshd = SshServer.setUpDefaultServer();
  sshd.setPort(9191);

  //
  // It's usually a good idea to give the host key generator a path,
  // so that if you restart the sshd server, the same key will be
  // used to authenticate the server.
  //
  sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider("hostkey.ser"));

  // auth object
  PasswordAuthenticator myAuthenticator = new MyPasswordAuth();
  sshd.setPasswordAuthenticator(myAuthenticator);
  
  //
  // That's the part you will usually have to write to customize the SSHD server.
  // The shell factory will be used to create a new shell each time a user logs in.
  // SSHD provides a single implementation that you can use if you want.
  // This implementation will create a process and delegate everything to it,
  // so it's mostly useful to launch the OS native shell.
  //
  //sshd.setShellFactory(new ProcessShellFactory(new String[] { "cmd", "/c" }));
  sshd.setShellFactory(new ProcessShellFactory( new String[] { "/bin/sh", "-i", "-l" }));
  
  //
  // SSHD provides a CommandFactory to support SCP that can be configure
  //  in the following way:
  ///
  sshd.setCommandFactory(new ScpCommandFactory());
  
  try {
    sshd.start();
    System.out.println("pure java sshd server started.");
  } catch (IOException e) {
    e.printStackTrace();
  }

1行目でSshServerオブジェクトを生成し、ポート番号に9191ポートを設定しています。
13行目で認証用オブジェクトを設定していますが、これはPasswordAuthenticatorインターフェースを実装したクラスを用意します。今回は次のようなMyPasswordAuthクラスを用意しました。

public class MyPasswordAuth implements PasswordAuthenticator {

  public boolean authenticate(String username, String password, ServerSession session) {
    System.out.println("username: "+username+", password: "+password);
    return true;
  }

}

authenticateメソッドに渡されるユーザID、パスワード、ServerSessionを使って認証しますが、この例ではとにかくture(認証OK)としています。

23行目でSshServerに設定しているProcessShellFactoryオブジェクトがサーバ側でコマンドを実行しており、内部ではProcessBuilderを使って外部コマンドを呼び出しています。

29行目ではSCP用のファクトリ・オブジェクトを設定しています。

ここまで出来たらSSHサーバを起動して、クライアントから接続してみましょう。

$ ssh -p 9191 username@localhost
The authenticity of host '[localhost]:9191' can't be established.
DSA key fingerprint is 09:8b:d5:47:5d:c6:3a:c3:05:41:23:85:ad:f5:d0:fc.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[localhost]:9191' (DSA) to the list of known hosts.
username@localhost's password:
sh: no job control in this shell

sh-3.00#  

確かにログインできます。但し、余分な空白が入ったり、対話的なコマンドは実行出来ないなどの制限があります(残念・・・)。
このあたりはサンプルコード23行目で設定しているProcessShellFactoryクラスを独自のクラス(Factory<Command>インタフェースを実装したクラス)に置き換えることで多少は改善しそうですが、僕は改行コードの動きが改善できず途中で諦めました。

これに対してSCPは特に問題無く動作します。性能面でも僕の環境ではネイテイブのSFTP/SCPツールと同等のスピードが出ました。さらにWidnows上で動作させた場合でもコピー可能です。

$ scp -P 9191 ~/Downloads/file.zip username@192.168.0.20:c:/tmp/tmp2.txt
username@192.168.0.20's password:
htmlparser1_6_20060610.zip                                                            100% 4244KB   2.1MB/s   00:02

リモート・シェル用途で使うにはきついですが、リモートのWindows PCにSCPでファイル転送したい場合には使えるかもしれませんね。



実用SSH 第2版―セキュアシェル徹底活用ガイド
Daniel J. Barrett Richard E. Silverman Robert G. Byrnes
オライリー・ジャパン
売り上げランキング: 219605


Java ネットワーク プログラミング 基礎からわかる 完全入門
永嶋 浩
技術評論社
売り上げランキング: 370959
  
Posted by netbuffalo at 18:55TrackBack(0)