sshjを試してみた

javaで作られているsshクライアントであるsshjを試してみました
https://github.com/hierynomus/sshj/blob/master/examples/src/main/java/net/schmizz/sshj/examples/LocalPF.java

単純にssh経由でコマンドを実行するだけでなくsshプロトコルを利用しているscpやsftpも利用できて、シンプルなターミナルも作れるので作業の自動化に役に立ちそうな気がします。 サンプルも簡単に動かすことができました。
https://github.com/hierynomus/sshj/tree/master/examples/src/main/java/net/schmizz/sshj/examples

ssh接続設定

  private SSHClient sshConnectSetting(String host, String username, String password) throws IOException {
    SSHClient ssh = new SSHClient();
    ssh.loadKnownHosts();
    ssh.connect(host);
    // keepAliveの感覚設定
    ssh.getConnection().getKeepAlive().setKeepAliveInterval(5);
    // 接続時のsshキーの指定はauthPublickeyを認証時のパスワードにはauthPasswordを使う
    // ssh.authPublickey(keyPath);
    ssh.authPassword(username,password);
    return ssh;
  }

ssh接続キーの指定にはSSHClientのauthPublickeyメソッッドを使います。認証時のパスワードが必要な場合はauthPasswordを呼び出します。

コマンド実行

public void sshjSample() throws IOException {
  final SSHClient ssh = sshConnectSetting("***", "***", "***");
  try {
    // コマンド実行
    sessionCommand(ssh.startSession(), "echo 'hello sshj' >> hello_sshj.txt", 5);
  } finally {
    ssh.disconnect();
  }
}
private void sessionCommand(Session session, String command, int timeout) throws IOException {
  try {
    final Session.Command cmd = session.exec(command);
    System.out.println(IOUtils.readFully(cmd.getInputStream()).toString());
    cmd.join(timeout, TimeUnit.SECONDS);
    System.out.println("\n** exit status: " + cmd.getExitStatus());
  } finally {
    session.close();
  }
}

scp

private void scpDownloadSample(SSHClient ssh, String downloadFilePath, String saveFileDir) throws IOException{
  ssh.newSCPFileTransfer().download(downloadFilePath, new FileSystemFile(saveFileDir));
}
private void scpUpload(SSHClient ssh, FileSystemFile uploadFile, String uploadPath) throws IOException{
  ssh.newSCPFileTransfer().upload(uploadFile, uploadPath);
}

sftp

private void sftpUploadSample(SSHClient ssh, FileSystemFile uploadFile, String uploadDir) throws IOException{
  final SFTPClient sftp = ssh.newSFTPClient();
  try {
    sftp.put(uploadFile, uploadDir);
  } finally {
    sftp.close();
  }
}

private void sftpUploadSample(SSHClient ssh, String downloadFilePath, String saveFileDir) throws IOException{
  final SFTPClient sftp = ssh.newSFTPClient();
  try {
    sftp.get(downloadFilePath, new FileSystemFile(saveFileDir));
  } finally {
    sftp.close();
  }
}

ローカルポートフォワード

private void localPortFowardSample(SSHClient ssh, String localHost, int localPort, String remoteHost, int remotePort) throws IOException{
  final LocalPortForwarder.Parameters params
          = new LocalPortForwarder.Parameters(localHost, localPort, remoteHost, remotePort);
  final ServerSocket ss = new ServerSocket();
  ss.setReuseAddress(true);
  ss.bind(new InetSocketAddress(params.getLocalHost(), params.getLocalPort()));
  try {
    ssh.newLocalPortForwarder(params, ss).listen();
  } finally {
    ss.close();
  }
}

リモートポートフォワード

private void remotePortFowardSample(SSHClient ssh, String remoteHost, int remotePort) throws IOException{
    try {
      ssh.getRemotePortForwarder().bind(
              new RemotePortForwarder.Forward(remotePort),
              new SocketForwardingConnectListener(new InetSocketAddress(remoteHost, remotePort)));

      ssh.getTransport().setHeartbeatInterval(30);

      // Something to hang on to so that the forwarding stays
      ssh.getTransport().join();
    }catch (IOException e){
      e.printStackTrace();
    }
  }

ターミナル

private void samplePTY(String host, String username, String password) throws IOException{
    final SSHClient ssh = new SSHClient();

    final File khFile = new File(OpenSSHKnownHosts.detectSSHDir(), "known_hosts");
    ssh.addHostKeyVerifier(new ConsoleKnownHostsVerifier(khFile, System.console()));

    ssh.connect(host);
    ssh.authPassword(username,password);
    try {

      // ssh.authPublickey(System.getProperty("user.name"));
      final Session session = ssh.startSession();
      try {

        session.allocateDefaultPTY();

        final Session.Shell shell = session.startShell();

        new StreamCopier(shell.getInputStream(), System.out, LoggerFactory.DEFAULT)
                .bufSize(shell.getLocalMaxPacketSize())
                .spawn("stdout");

        new StreamCopier(shell.getErrorStream(), System.err, LoggerFactory.DEFAULT)
                .bufSize(shell.getLocalMaxPacketSize())
                .spawn("stderr");

        // Now make System.in act as stdin. To exit, hit Ctrl+D (since that results in an EOF on System.in)
        // This is kinda messy because java only allows console input after you hit return
        // But this is just an example... a GUI app could implement a proper PTY
        new StreamCopier(System.in, shell.getOutputStream(), LoggerFactory.DEFAULT)
                .bufSize(shell.getRemoteMaxPacketSize())
                .copy();

      } finally {
        session.close();
      }

    } finally {
      ssh.disconnect();
    }
  }