java - pure - libreria jcraft
Biblioteca SSH para Java (7)
¿Alguien sabe de una buena biblioteca para el inicio de sesión de SSH desde Java?
Acabo de descubrir sshj , que parece tener una API mucho más concisa que JSCH (pero requiere Java 6). La documentación es principalmente por ejemplos en el repositorio en este punto, y por lo general eso es suficiente para que busque en otro lado, pero parece lo suficientemente bueno como para darle una oportunidad en un proyecto que acabo de comenzar.
Actualización: el proyecto GSOC y el código allí no están activos, pero esto es: https://github.com/hierynomus/sshj
hierynomus asumió como mantenedor desde principios de 2015. Aquí está el enlace de Github más antiguo, que ya no se mantiene:
Hubo un proyecto de GSOC:
http://code.google.com/p/commons-net-ssh/
La calidad del código parece ser mejor que JSch, que, si bien es una implementación completa y funcional, carece de documentación. La página del proyecto detecta una próxima versión beta, el último compromiso con el repositorio fue a mediados de agosto.
Compare las API:
http://code.google.com/p/commons-net-ssh/
SSHClient ssh = new SSHClient();
//ssh.useCompression();
ssh.loadKnownHosts();
ssh.connect("localhost");
try {
ssh.authPublickey(System.getProperty("user.name"));
new SCPDownloadClient(ssh).copy("ten", "/tmp");
} finally {
ssh.disconnect();
}
Session session = null;
Channel channel = null;
try {
JSch jsch = new JSch();
session = jsch.getSession(username, host, 22);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.setPassword(password);
session.connect();
// exec ''scp -f rfile'' remotely
String command = "scp -f " + remoteFilename;
channel = session.openChannel("exec");
((ChannelExec) channel).setCommand(command);
// get I/O streams for remote scp
OutputStream out = channel.getOutputStream();
InputStream in = channel.getInputStream();
channel.connect();
byte[] buf = new byte[1024];
// send ''/0''
buf[0] = 0;
out.write(buf, 0, 1);
out.flush();
while (true) {
int c = checkAck(in);
if (c != ''C'') {
break;
}
// read ''0644 ''
in.read(buf, 0, 5);
long filesize = 0L;
while (true) {
if (in.read(buf, 0, 1) < 0) {
// error
break;
}
if (buf[0] == '' '') {
break;
}
filesize = filesize * 10L + (long) (buf[0] - ''0'');
}
String file = null;
for (int i = 0;; i++) {
in.read(buf, i, 1);
if (buf[i] == (byte) 0x0a) {
file = new String(buf, 0, i);
break;
}
}
// send ''/0''
buf[0] = 0;
out.write(buf, 0, 1);
out.flush();
// read a content of lfile
FileOutputStream fos = null;
fos = new FileOutputStream(localFilename);
int foo;
while (true) {
if (buf.length < filesize) {
foo = buf.length;
} else {
foo = (int) filesize;
}
foo = in.read(buf, 0, foo);
if (foo < 0) {
// error
break;
}
fos.write(buf, 0, foo);
filesize -= foo;
if (filesize == 0L) {
break;
}
}
fos.close();
fos = null;
if (checkAck(in) != 0) {
System.exit(0);
}
// send ''/0''
buf[0] = 0;
out.write(buf, 0, 1);
out.flush();
channel.disconnect();
session.disconnect();
}
} catch (JSchException jsche) {
System.err.println(jsche.getLocalizedMessage());
} catch (IOException ioe) {
System.err.println(ioe.getLocalizedMessage());
} finally {
channel.disconnect();
session.disconnect();
}
}
Echa un vistazo a SSHD , recientemente lanzado, que se basa en el proyecto Apache MINA.
Hay una nueva versión de Jsch en github: https://github.com/vngx/vngx-jsch Algunas de las mejoras incluyen: javadoc completo, rendimiento mejorado, manejo de excepciones mejorado y mejor adherencia de especificaciones de RFC. Si desea contribuir de alguna manera, abra un problema o envíe una solicitud de extracción.
Tomé la respuesta de miku y el código de ejemplo jsch. Luego tuve que descargar varios archivos durante la sesión y conservar las marcas de tiempo originales . Este es mi código de ejemplo de cómo hacerlo, probablemente muchas personas lo encuentren útil. Por favor, ignorar la función de nombre de archivo () es mi propio uso.
package examples;
import com.jcraft.jsch.*;
import java.io.*;
import java.util.*;
public class ScpFrom2 {
public static void main(String[] args) throws Exception {
Map<String,String> params = parseParams(args);
if (params.isEmpty()) {
System.err.println("usage: java ScpFrom2 "
+ " user=myid password=mypwd"
+ " host=myhost.com port=22"
+ " encoding=<ISO-8859-1,UTF-8,...>"
+ " /"remotefile1=/some/file.png/""
+ " /"localfile1=file.png/""
+ " /"remotefile2=/other/file.txt/""
+ " /"localfile2=file.txt/""
);
return;
}
// default values
if (params.get("port") == null)
params.put("port", "22");
if (params.get("encoding") == null)
params.put("encoding", "ISO-8859-1"); //"UTF-8"
Session session = null;
try {
JSch jsch=new JSch();
session=jsch.getSession(
params.get("user"), // myuserid
params.get("host"), // my.server.com
Integer.parseInt(params.get("port")) // 22
);
session.setPassword( params.get("password") );
session.setConfig("StrictHostKeyChecking", "no"); // do not prompt for server signature
session.connect();
// this is exec command and string reply encoding
String encoding = params.get("encoding");
int fileIdx=0;
while(true) {
fileIdx++;
String remoteFile = params.get("remotefile"+fileIdx);
String localFile = params.get("localfile"+fileIdx);
if (remoteFile == null || remoteFile.equals("")
|| localFile == null || localFile.equals("") )
break;
remoteFile = filenameHack(remoteFile);
localFile = filenameHack(localFile);
try {
downloadFile(session, remoteFile, localFile, encoding);
} catch (Exception ex) {
ex.printStackTrace();
}
}
} catch(Exception ex) {
ex.printStackTrace();
} finally {
try{ session.disconnect(); } catch(Exception ex){}
}
}
private static void downloadFile(Session session,
String remoteFile, String localFile, String encoding) throws Exception {
// send exec command: scp -p -f "/some/file.png"
// -p = read file timestamps
// -f = From remote to local
String command = String.format("scp -p -f /"%s/"", remoteFile);
System.console().printf("send command: %s%n", command);
Channel channel=session.openChannel("exec");
((ChannelExec)channel).setCommand(command.getBytes(encoding));
// get I/O streams for remote scp
byte[] buf=new byte[32*1024];
OutputStream out=channel.getOutputStream();
InputStream in=channel.getInputStream();
channel.connect();
buf[0]=0; out.write(buf, 0, 1); out.flush(); // send ''/0''
// reply: T<mtime> 0 <atime> 0/n
// times are in seconds, since 1970-01-01 00:00:00 UTC
int c=checkAck(in);
if(c!=''T'')
throw new IOException("Invalid timestamp reply from server");
long tsModified = -1; // millis
for(int idx=0; ; idx++){
in.read(buf, idx, 1);
if(tsModified < 0 && buf[idx]=='' '') {
tsModified = Long.parseLong(new String(buf, 0, idx))*1000;
} else if(buf[idx]==''/n'') {
break;
}
}
buf[0]=0; out.write(buf, 0, 1); out.flush(); // send ''/0''
// reply: C0644 <binary length> <filename>/n
// length is given as a text "621873" bytes
c=checkAck(in);
if(c!=''C'')
throw new IOException("Invalid filename reply from server");
in.read(buf, 0, 5); // read ''0644 '' bytes
long filesize=-1;
for(int idx=0; ; idx++){
in.read(buf, idx, 1);
if(buf[idx]=='' '') {
filesize = Long.parseLong(new String(buf, 0, idx));
break;
}
}
// read remote filename
String origFilename=null;
for(int idx=0; ; idx++){
in.read(buf, idx, 1);
if(buf[idx]==''/n'') {
origFilename=new String(buf, 0, idx, encoding); // UTF-8, ISO-8859-1
break;
}
}
System.console().printf("size=%d, modified=%d, filename=%s%n"
, filesize, tsModified, origFilename);
buf[0]=0; out.write(buf, 0, 1); out.flush(); // send ''/0''
// read binary data, write to local file
FileOutputStream fos = null;
try {
File file = new File(localFile);
fos = new FileOutputStream(file);
while(filesize > 0) {
int read = Math.min(buf.length, (int)filesize);
read=in.read(buf, 0, read);
if(read < 0)
throw new IOException("Reading data failed");
fos.write(buf, 0, read);
filesize -= read;
}
fos.close(); // we must close file before updating timestamp
fos = null;
if (tsModified > 0)
file.setLastModified(tsModified);
} finally {
try{ if (fos!=null) fos.close(); } catch(Exception ex){}
}
if(checkAck(in) != 0)
return;
buf[0]=0; out.write(buf, 0, 1); out.flush(); // send ''/0''
System.out.println("Binary data read");
}
private static int checkAck(InputStream in) throws IOException {
// b may be 0 for success
// 1 for error,
// 2 for fatal error,
// -1
int b=in.read();
if(b==0) return b;
else if(b==-1) return b;
if(b==1 || b==2) {
StringBuilder sb=new StringBuilder();
int c;
do {
c=in.read();
sb.append((char)c);
} while(c!=''/n'');
throw new IOException(sb.toString());
}
return b;
}
/**
* Parse key=value pairs to hashmap.
* @param args
* @return
*/
private static Map<String,String> parseParams(String[] args) throws Exception {
Map<String,String> params = new HashMap<String,String>();
for(String keyval : args) {
int idx = keyval.indexOf(''='');
params.put(
keyval.substring(0, idx),
keyval.substring(idx+1)
);
}
return params;
}
private static String filenameHack(String filename) {
// It''s difficult reliably pass unicode input parameters
// from Java dos command line.
// This dirty hack is my very own test use case.
if (filename.contains("${filename1}"))
filename = filename.replace("${filename1}", "Korilla ABC ÅÄÖ.txt");
else if (filename.contains("${filename2}"))
filename = filename.replace("${filename2}", "test2 ABC ÅÄÖ.txt");
return filename;
}
}
http://code.google.com/p/connectbot/ , compilar src / com / trilead / ssh2 en windows linux o android, puede crear un reenviador de puerto local o crear un reenviador de puerto dinámico u otro
Java Secure Channel (JSCH) es una biblioteca muy popular, utilizada por maven, ant y eclipse. Es de código abierto con una licencia de estilo BSD.