jsch_
JSch
uma biblioteca Java para
facilitar o uso do SSH
Executando comandos remotos e fazendo
conexão SSH dentro de programas Java
Durante a leitura do artigo iremos ver como a biblioteca
JSch pode facilitar o uso do protocolo SSH. Várias tarefas relacionadas ao uso do protocolo podem ser executadas facilmente através de programas Java usando esta biblioteca.
André Luís Fonseca | [email protected]
é formado em Ciência da Computação pela Universidade Federal de São Carlos (UFSCar). Trabalha na empresa
NTT Data Brasil. Com mais de 11 anos de experiência, já trabalhou em empresas de diversos setores como:
Telecom, Bancos e Indústria utilizando Java, PHP e C. Possui as certificações SCJP, SCWCD, SCBCD e SCEA (I).
O
SSH é um protocolo de rede
que suporta criptografia.
Ele é utilizado para realizar
a troca segura de dados entre
servidores, execução remota de
serviços ou comandos além de
outros serviços entre dois
computadores ligados em
rede. O protocolo SSH cria
um canal seguro por cima de
uma rede insegura. O cliente
SSH é um programa que usa
o protocolo para se conectar a um
computador remoto. O servidor
SSH é um programa que usa o
protocolo para aceitar as conexões de computadores remotos.
O protocolo pode ser usado por muitas aplicações em
vários sistemas operacionais
diferentes, Unix, Linux, Windows etc. Em 2006 foi criada uma
/ 48
versão do protocolo chamada de SSH-2 que foi adotada como padrão e é usada até hoje. Mais detalhes
podem ser encontrados na RFC relativa ao protocolo
(consultar referências).
Algumas das tarefas que podem ser executadas
com esse protocolo incluem:
» logar em uma shell de um computador remoto
» executar comandos em um computador remoto
» realizar uma cópia segura de arquivos entre
computadores
» juntamente com o programa rsync realizar
operações de backup, cópia e espelhamento de
arquivos de maneira eficiente e segura entre
computadores
» redirecionar pacotes de dados através da criação de um túnel
A biblioteca JSch (Java Secure Shell) é uma implementação de um cliente SSH escrita em Java. Foi
criada por uma empresa japonesa e disponibilizada
através da licença BSD. A licença BSD permite que
o software distribuído sobre essa licença seja incor-
porado a produtos proprietários. Algumas aplicações
que usam o JSch são: ANT, Eclipse, Netbeans, Maven,
JiRA, entre outras.
Além do JSch temos outras bibliotecas criadas
pela mesma empresa que são:
» WiredX e WeirdX – X Window Systems – um
X Window System é um programa e um protocolo de rede que prove uma interface gráfica
GUI para administração remota de servidores
(o primeiro é comercial, o segundo usa licença
GPL)
» JZlib – implementação em Java da biblioteca
Zlib de compressão de arquivos
» JCTerm – um emulador de terminal escrito em
Java para o protocolo SSH
» JOrbis – implementação em Java para trabalhar com compressão de arquivos de áudio
» JHttpTunnel – implementação em Java de um
Túnel HTTP
» JRexec – um cliente REXEC escrito em Java
Este artigo está focado apenas na utilização da
biblioteca JSch. Mais detalhes dos outros projetos
podem ser encontrados no site da empresa (consultar referências).
Iniciando com o JSch, criando o
primeiro exemplo
No momento da escrita deste artigo a última
versão da biblioteca era a 0.1.4.9. No site do projeto
pode ser feito o download do JAR apenas ou então
do arquivo ZiP o qual contém vários exemplos que
podem ser testados através do ANT.
Após o download crie um novo projeto Java na
sua iDE de preferência e adicione o JAR do JSch no
CLASSPATH da aplicação, no meu caso estou usando
o Eclipse.
Para realizar uma conexão SSH com o host remoto (servidor) os seguintes passos precisam ser
seguidos:
criar um objeto JSch – onde ficam as configurações básicas como usuário e senha para a
conexão
» criar uma sessão – a sessão deve ser recuperada do objeto JSch
» conectar a sessão no host remoto passando as
credenciais do usuário
» abrir um canal no host remoto de um determinado tipo usando a sessão aberta no passo
anterior
» executar os comandos desejados no canal
aberto com o host remoto
» fechar o canal
» fechar a sessão com o host
A seguir, temos a implementação destes passos
através de código Java.
»
Listagem 1. Primeiro exemplo usando a biblioteca
JSch.
/* As configurações da sessão são feitas no objeto jSch */
JSch jSch = new JSch();
int port = 22;
String host = “localhost”;
String username = “andre.fonseca”;
Session session = jSch.getSession(username, host, port);
session.setPassword(“pass”);
/*
* Conecta ao host sem pedir confirmação caso contrário
* você pode adicionar a lista de hosts conhecidos
* usando o método setKnowHosts da classe JSch. Em
* ambiente Linux recebe como parametro uma string
* que aponta para o arquivo home/foo/.ssh/known_hosts
*/
Properties config = new Properties();
config.put(“StrictHostKeyChecking”, “no”);
session.setConfig(config);
/* Conecta a sessão usando um timeout */
session.connect(3000);
/*
Entrada e Saída em Java
Entradas e Saídas de programas em Java são representadas por Streams ou Fluxos. Uma Stream pode representar um arquivo em disco, um dispositivo externo, um programa, um vetor em memória, entre outras
coisas. São vários os tipos de dados suportados por uma Stream, como, por exemplo: bytes simples, tipos
primitivos, caracteres, objetos etc.
Uma Stream pode apenas transmitir os dados da origem para o destino, ou então manipular ou transformar os dados de entrada antes de enviá-los para a saída. Sempre representa o mesmo modelo de dados:
uma Stream é uma sequência ordenada de bytes de tamanho indefinido.
O Java possui três objetos representando Streams que são: System.in, System.out e System.err. Esses três
objetos são inicializados automaticamente quando a JVM inicia. O primeiro representa a entrada padrão
(normalmente o teclado ou o console dos programas), o segundo representa a saída padrão enquanto o
último representa a saída padrão de erros.
49 \
* Abre um canal com a sessão do tipo shell
* para alterar o tipo altere o parâmetro do método
*/
Channel channel = session.openChannel(“shell”);
/* agora eu posso realizar as operações necessárias no
servidor remoto */
/* Desconecta do canal */
channel.disconnect();
/* Desconecta da sessão */
session.disconnect();
Uma sessão representa uma conexão com o servidor
SSH. Uma sessão pode ter um ou mais canais abertos
com o servidor ao mesmo tempo. Os tipos existentes
de canais são:
» shell – a stream aberta com o servidor SSH possui tanto os comandos como os parâmetros de
entrada dos comandos, funciona como se estivéssemos digitando comandos interativamente
na shell remota
» exec – os comandos são passados através do
método setCommand antes do canal estar conectado com o servidor, funciona como se estivéssemos executando um shell script na máquina local
» subsystem – neste caso as configurações do
servidor SSH decidem o que deve ser feito, não
a shell remota. Um uso comum é quando queremos fazer SFTP para o servidor SSH
» direct-tcpip – este canal permite o redirecionamento de streams para e do servidor SSH
» sftp – este canal se conecta a um servidor SFTP
Figura 1. Selecione o pacote openssh na hora da instalação do
Cygwin.
Figura 2. Serviço sshd iniciado no Windows.
Testando outros exemplos do JSch
Conforme já mencionamos, o JSch vem com vários exemplos na pasta examples do arquivo ZiP. Vamos falar agora um pouco dos principais.
Shell.java
Este exemplo possibilita que o programa se conecte ao servidor sshd e retorne o prompt da shell.
Ao rodar o exemplo no Eclipse você receberá um
popup perguntando o usuário de entrada, preencha
com o usuário que você usou para instalar o pacote
Preparando o ambiente
Precisamos de um servidor SSH para testar os openssh no Cygwin (usuário Windows).
exemplos que vêm junto com o download do JSch.
A fim de testar estes exemplos localmente sem a
necessidade de um servidor remoto (em uma rede de
computadores) iremos instalar o pacote openssh do
Cygwin. O Cygwin é um emulador de sistemas Linux/
Unix para Windows. O openssh possui várias ferramentas de conexão SSH além de uma implementação Figura 3. Preencha com o usuário do Windows.
de um servidor SSH (conhecido como sshd).
Na sequência um novo popup irá perguntar a sePara instalar o Cygwin basta fazer o download do
arquivo setup.exe e seguir os passos descritos no link nha do usuário.
“instalando o Cygwin” nas referências do artigo (não
se esqueça de selecionar o pacote openssh na hora da
instalação).
Após configurar o openssh no Cygwin, podemos
verificar que um novo serviço foi instalado no Windows (consultar o link “Configurando um Servidor SSH Figura 4. Preencha com a senha do usuário Windows.
no Cygwin” nas referências do artigo).
/ 50
Como não estamos armazenando a chave de autenticação no nosso computador toda vez que conectarmos no servidor “localhost” (serviço sshd rodando
no Cygwin) iremos receber a mensagem abaixo. Em
ambientes Linux esta chave é armazenada no arquivo
~/.ssh/known_hosts. Clique em “Yes” para continuar.
// conecta no canal
channel.connect();
// imprime no console do Eclipse o resultado do comando
executado
byte[] tmp=new byte[1024];
while(true){
while(in.available()>0){
int i=in.read(tmp, 0, 1024);
if(i<0)break;
}
Figura 5. Mensagem de “Warning”.
Listagem 2. Conectando no servidor sshd e recuperando o prompt de comando.
// abre uma sessão do tipo shell
Channel channel=session.openChannel(“shell”);
// seta a Input Stream padrão (console do Eclipse)
channel.setInputStream(System.in);
// seta a Output Stream padrão (console do Eclipse)
channel.setOutputStream(System.out);
Exec.java
}
System.out.print(new String(tmp, 0, i));
if(channel.isClosed()){
System.out.println(“exit-status:
“+channel.getExitStatus());
break;
}
ScpTo.java
Este exemplo mostra como copiar um arquivo da
máquina local para o servidor remoto. Antes de rodar
o exemplo você deve editar as configurações do Eclipse (Run Configurations) para passar como argumento
a string “file1 user@remotehost:file2” onde file1 é o
caminho para o arquivo na máquina local e file2 é o
caminho para o arquivo na máquina remota (Cygwin).
Este exemplo abre um canal do tipo “exec” e pergunta ao usuário que comando deve ser executado no
servidor remoto. Os comandos podem ser concatenados usando o pipe “|”. Exibe no console do Eclipse o
resultado da execução do comando.
Figura 7. Digite nos argumentos da JVM os caminhos para a cópia
do arquivo.
Figura 6. Digite o comando a ser executado no servidor remoto.
Após rodar o exemplo você pode verificar no terminal do Cygwin que o arquivo foi copiado para a
pasta home.
Listagem 3. Executando comandos no servidor
remoto.
// usuário digita o comando a ser executado
String command=JOptionPane.showInputDialog(
“Enter command”,
“set|grep SSH”);
// abre uma sessão do tipo “exec”
Channel channel=session.openChannel(“exec”);
// atribuir para a sessão o comando digitado pelo usuário
((ChannelExec)channel).setCommand(command);
// define a saída de erros para o console do Eclipse
((ChannelExec)channel).setErrStream(System.err);
// recupera a stream de entrada do canal
InputStream in=channel.getInputStream();
Figura 8. Arquivo copiado para a máquina remota.
Listagem 4. Copiando um arquivo da máquina local
para a máquina remota.
// cria o comando e adiciona no canal do tipo “exec”
String command = “scp -p -t” + rfile;
51 \
Channel channel = session.openChannel(“exec”);
((ChannelExec) channel).setCommand(command);
// recupera as streams de entrada/saida do scp remoto
OutputStream out = channel.getOutputStream();
InputStream in = channel.getInputStream();
// envia o comando “C0644 tamanho_arquivo nome_
arquivo”, onde o nome_arquivo
// não deve possuir ‘/’
long filesize = _lfile.length();
command = “C0644 “ + filesize + “ “;
if (lfile.lastIndexOf(‘/’) > 0) {
command += lfile.substring(lfile.lastIndexOf(‘/’) + 1);
} else {
command += lfile;
}
command += “\n”;
out.write(command.getBytes());
out.flush();
// envia o conteudo do arquivo para o servidor remoto
fis = new FileInputStream(lfile);
byte[] buf = new byte[1024];
while (true) {
int len = fis.read(buf, 0, buf.length);
if (len <= 0)
break;
out.write(buf, 0, len); // out.flush();
}
fis.close();
fis = null;
// send ‘\0’
buf[0] = 0;
out.write(buf, 0, 1);
out.flush();
out.close();
Logger.java
Este exemplo mostra como criar um logger para
recuperar as informações durante a conexão com o
servidor.
Listagem 5. Listando informações da conexão SSH
com o servidor no console do Eclipse.
NFO: Connecting to localhost port 22
INFO: Connection established
INFO: Remote version string: SSH-2.0-OpenSSH_6.0
INFO: Local version string: SSH-2.0-JSCH-0.1.49
INFO:
CheckCiphers:
aes256-ctr,aes192-ctr,aes128ctr,aes256-cbc,aes192-cbc,aes128-cbc,3des-ctr,arcfour,arcf
our128,arcfour256
INFO: CheckKexes: diffie-hellman-group14-sha1
INFO: diffie-hellman-group14-sha1 is not available.
INFO: SSH_MSG_NEWKEYS sent
INFO: SSH_MSG_NEWKEYS received
/ 52
I INFO: SSH_MSG_SERVICE_REQUEST sent
INFO: SSH_MSG_SERVICE_ACCEPT received
INFO: Authentications that can continue: publickey,keyboardinteractive,password
INFO: Next authentication method: publickey
INFO: Authentications that can continue: keyboardinteractive,password
INFO: Next authentication method: keyboard-interactive
INFO: Authentications that can continue: password
INFO: Next authentication method: password
INFO: Authentication succeeded (password).
Listagem 6. Criando um Logger para exibir as informações da conexão SSH com o servidor.
// seta um logger personalizado
JSch.setLogger(new MyLogger());
// define uma classe estatica para implementação
de um logger
// personalizado
public static class MyLogger implements
com.jcraft.jsch.Logger {
static java.util.Hashtable name=
new java.util.Hashtable();
static{
name.put(new Integer(DEBUG), “DEBUG: “);
name.put(new Integer(INFO), “INFO: “);
name.put(new Integer(WARN), “WARN: “);
name.put(new Integer(ERROR), “ERROR: “);
name.put(new Integer(FATAL), “FATAL: “);
}
public boolean isEnabled(int level){
return true;
}
public void log(int level, String message){
System.err.print(name.get(new Integer(level)));
System.err.println(message);
}
}
X11Forwarding.java
Este exemplo mostra como fazer “X11 Forwarding”. Esta técnica permite que você consiga executar aplicações gráficas no servidor remoto sendo que
a interface será executada na máquina local. Ou seja,
eu vou executar a aplicação no servidor e vou conseguir ver a interface na minha máquina local.
Para conseguir rodar este exemplo precisamos
iniciar o Cygwin/Xserver. No menu iniciar, na opção
Cygwin-X clique em “XWin Server”. Na barra de tarefas deve aparecer um ícone no formato de um “X”
mostrando que o XServer foi iniciado.
Rode o exemplo no Eclipse. Depois defina o
display digitando o seguinte comando export DISPLAY=’127.0.0.1:0’ no Console do Eclipse.
Agora você pode iniciar uma aplicação “GUi” diretamente pelo console do Eclipse, tente, por exemplo, rodando xlogo.exe & ou xclock.exe & no console.
Figura 10. Listando as opções disponíveis ao fazer o SFTP no console do Eclipse.
Figura 9. Iniciando o Cygwin/XServer.
Listagem 7. Definindo as configurações para fazer o
X11 Forwarding.
String xhost=”127.0.0.1”;
int xport=0;
// define as propriedades xhost e xport
// necessárias para fazer o X11 Forwarding
session.setx11Host(xhost);
session.setX11Port(xport+6000);
Channel channel=session.openChannel(“shell”);
channel.setXForwarding(true);
// seta a Input Stream padrão (console do Eclipse)
channel.setInputStream(System.in);
// seta a Output Stream padrão (console do Eclipse)
channel.setOutputStream(System.out);
Sftp.java
Este exemplo abre um canal do tipo “sftp” (Secure File Transfer Protocol) com o servidor remoto possibilitando que arquivos sejam acessados, transferidos e manuseados de forma segura entre a máquina
local e o servidor.
Ao executar o exemplo no Eclipse, o usuário irá
receber um prompt para se conectar no servidor e realizar as operações desejadas. Digite help no prompt
(console do Eclipse) para ver as opções disponíveis.
Considerações Finais
A biblioteca JSch (Java Secure Shell) é uma implementação de um cliente SSH escrita em Java.
Podemos utilizar essa biblioteca dentro dos nossos
programas Java para facilitar a comunicação com servidores remotos através do protocolo SSH. Várias tarefas podem ser executadas como: execução remota
de comandos, SCP, SFTP, X11 Forwarding etc.
Essas funcionalidades podem ser integradas facilmente com outros programas já existentes facilitando a automatização de tarefas repetitivas, como
backup, transferência de arquivos, entre outras.
/referências
> Site do JCraft (contendo todos os projetos inclusive a
biblioteca JSch): http://www.jcraft.com/
> Download do JAR do JSch : http://sourceforge.net/
projects/jsch/files/jsch.jar/0.1.49/jsch-0.1.49.jar/download
> Download do ZIP do JSch: http://sourceforge.net/
projects/jsch/files/jsch/0.1.49/jsch-0.1.49.zip/download
> Javadoc do projeto (não oficial): http://epaul.github.
com/jsch-documentation/javadoc/com/jcraft/jsch/packagesummary.html
> Wiki: http://sourceforge.net/apps/mediawiki/jsch/index.
php?title=Main_Page
> Instalando o Cygwin: http://cygwin.com/install.html
Configurando um Servidor SSH no Cygwin: http://
lifehacker.com/205090/geek-to-live--set-up-a-personalhome-ssh-server
> Arquitetura do Protocolo SSH: http://tools.ietf.org/html/
rfc4251
> I/O Streams: http://docs.oracle.com/javase/tutorial/
essential/io/streams.html
53 \
Download

JSch – Uma biblioteca Java para facilitar o uso do SSH