com.pastdev.jsch.DefaultSessionFactory Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsch-extension Show documentation
Show all versions of jsch-extension Show documentation
A set of extensions on top of JSch providing a full SCP protocol implementation, tunneling including multi-hop, a Java 7 FileSystem like implementation for Java 6 and remote command execution
The newest version!
package com.pastdev.jsch;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jcraft.jsch.Identity;
import com.jcraft.jsch.IdentityRepository;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Proxy;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;
import com.jcraft.jsch.agentproxy.AgentProxyException;
import com.jcraft.jsch.agentproxy.Connector;
import com.jcraft.jsch.agentproxy.ConnectorFactory;
import com.jcraft.jsch.agentproxy.RemoteIdentityRepository;
/**
* The default implementation of {@link com.pastdev.jsch.SessionFactory
* SessionFactory}. This class provides sane defaults for all
* conventional configuration including
*
*
* username: System property user.name
* hostname: localhost
* port: 22
* .ssh directory: System property jsch.dotSsh
, or system
* property user.home
concatenated with "/.ssh"
* known hosts: System property jsch.knownHosts.file
or,
* .ssh directory concatenated with "/known_hosts"
.
* private keys: First checks for an agent proxy using
* {@link ConnectorFactory#createConnector()}, then system property
* jsch.privateKey.files
split on ","
, otherwise, .ssh
* directory concatenated with all 3 of "/id_rsa"
,
* "/id_dsa"
, and "/id_ecdsa"
if they exist.
*
*/
public class DefaultSessionFactory implements SessionFactory {
private static Logger logger = LoggerFactory.getLogger( DefaultSessionFactory.class );
public static final String PROPERTY_JSCH_DOT_SSH = "jsch.dotSsh";
public static final String PROPERTY_JSCH_KNOWN_HOSTS_FILE = "jsch.knownHosts.file";
public static final String PROPERTY_JSCH_PRIVATE_KEY_FILES = "jsch.privateKey.files";
private Map config;
private File dotSshDir;
private String hostname;
private JSch jsch;
private String password;
private int port = SSH_PORT;
private Proxy proxy;
private UserInfo userInfo;
private String username;
/**
* Creates a default DefaultSessionFactory.
*/
public DefaultSessionFactory() {
this( null, null, null );
}
/**
* Constructs a DefaultSessionFactory with the supplied properties.
*
* @param username
* The username
* @param hostname
* The hostname
* @param port
* The port
*/
public DefaultSessionFactory( String username, String hostname, Integer port ) {
JSch.setLogger( new Slf4jBridge() );
jsch = new JSch();
try {
setDefaultIdentities();
}
catch ( JSchException e ) {
logger.warn( "Unable to set default identities: ", e );
}
try {
setDefaultKnownHosts();
}
catch ( JSchException e ) {
logger.warn( "Unable to set default known_hosts: ", e );
}
if ( username == null ) {
this.username = System.getProperty( "user.name" ).toLowerCase();
}
else {
this.username = username;
}
if ( hostname == null ) {
this.hostname = "localhost";
}
else {
this.hostname = hostname;
}
if ( port == null ) {
this.port = 22;
}
else {
this.port = port;
}
}
private DefaultSessionFactory( JSch jsch, String username, String hostname, int port, Proxy proxy ) {
this.jsch = jsch;
this.username = username;
this.hostname = hostname;
this.port = port;
this.proxy = proxy;
}
private void clearIdentityRepository() throws JSchException {
jsch.setIdentityRepository( null ); // revert to default identity repo
jsch.removeAllIdentity();
}
private File dotSshDir() {
if ( dotSshDir == null ) {
String dotSshString = System.getProperty( PROPERTY_JSCH_DOT_SSH );
if ( dotSshString != null ) {
dotSshDir = new File( dotSshString );
}
else {
dotSshDir = new File(
new File( System.getProperty( "user.home" ) ),
".ssh" );
}
}
return dotSshDir;
}
@Override
public String getHostname() {
return hostname;
}
@Override
public int getPort() {
return port;
}
@Override
public Proxy getProxy() {
return proxy;
}
@Override
public String getUsername() {
return username;
}
@Override
public UserInfo getUserInfo() {
return userInfo;
}
@Override
public Session newSession() throws JSchException {
Session session = jsch.getSession( username, hostname, port );
if ( config != null ) {
for ( String key : config.keySet() ) {
session.setConfig( key, config.get( key ) );
}
}
if ( proxy != null ) {
session.setProxy( proxy );
}
if ( password != null ) {
session.setPassword( password );
}
if ( userInfo != null ) {
session.setUserInfo( userInfo );
}
return session;
}
@Override
public SessionFactoryBuilder newSessionFactoryBuilder() {
return new SessionFactoryBuilder( jsch, username, hostname, port, proxy, config, userInfo ) {
@Override
public SessionFactory build() {
DefaultSessionFactory sessionFactory = new DefaultSessionFactory( jsch, username, hostname, port, proxy );
sessionFactory.config = config;
sessionFactory.password = password;
sessionFactory.userInfo = userInfo;
return sessionFactory;
}
};
}
/**
* Sets the configuration options for the sessions created by this factory.
* This method will replace the current SessionFactory config
* map. If you want to add, rather than replace, see
* {@link #setConfig(String, String)}. All of these options will be added
* one at a time using
* {@link com.jcraft.jsch.Session#setConfig(String, String)
* Session.setConfig(String, String)}. Details on the supported options can
* be found in the source for {@link com.jcraft.jsch.Session#applyConfig()}.
*
* @param config
* The configuration options
*
* @see com.jcraft.jsch.Session#setConfig(java.util.Hashtable)
* @see com.jcraft.jsch.Session#applyConfig()
*/
public void setConfig( Map config ) {
this.config = config;
}
/**
* Adds a single configuration options for the sessions created by this
* factory. Details on the supported options can be found in the source for
* {@link com.jcraft.jsch.Session#applyConfig()}.
*
* @param key
* The name of the option
* @param value
* The value of the option
*
* @see #setConfig(Map)
* @see com.jcraft.jsch.Session#setConfig(java.util.Hashtable)
* @see com.jcraft.jsch.Session#applyConfig()
*/
public void setConfig( String key, String value ) {
if ( config == null ) {
config = new HashMap();
}
config.put( key, value );
}
private void setDefaultKnownHosts() throws JSchException {
String knownHosts = System.getProperty( PROPERTY_JSCH_KNOWN_HOSTS_FILE );
if ( knownHosts != null && !knownHosts.isEmpty() ) {
setKnownHosts( knownHosts );
}
else {
File knownHostsFile = new File( dotSshDir(), "known_hosts" );
if ( knownHostsFile.exists() ) {
setKnownHosts( knownHostsFile.getAbsolutePath() );
}
}
}
private void setDefaultIdentities() throws JSchException {
boolean identitiesSet = false;
try {
Connector connector = ConnectorFactory.getDefault()
.createConnector();
if ( connector != null ) {
logger.info( "An AgentProxy Connector was found, check for identities" );
RemoteIdentityRepository repository = new RemoteIdentityRepository( connector );
Vector identities = repository.getIdentities();
if ( identities.size() > 0 ) {
logger.info( "Using AgentProxy identities: {}", identities );
setIdentityRepository( repository );
identitiesSet = true;
}
}
}
catch ( AgentProxyException e ) {
logger.debug( "Failed to load any keys from AgentProxy:", e );
}
if ( !identitiesSet ) {
String privateKeyFilesString = System.getProperty( PROPERTY_JSCH_PRIVATE_KEY_FILES );
if ( privateKeyFilesString != null && !privateKeyFilesString.isEmpty() ) {
logger.info( "Using local identities from {}: {}",
PROPERTY_JSCH_PRIVATE_KEY_FILES, privateKeyFilesString );
setIdentitiesFromPrivateKeys( Arrays.asList( privateKeyFilesString.split( "," ) ) );
identitiesSet = true;
}
}
if ( !identitiesSet ) {
List privateKeyFiles = new ArrayList();
for ( File file : new File[] {
new File( dotSshDir(), "id_rsa" ),
new File( dotSshDir(), "id_dsa" ),
new File( dotSshDir(), "id_ecdsa" ) } ) {
if ( file.exists() ) {
privateKeyFiles.add( file.getAbsolutePath() );
}
}
logger.info( "Using local identities: {}", privateKeyFiles );
setIdentitiesFromPrivateKeys( privateKeyFiles );
}
}
/**
* Sets the hostname.
*
* @param hostname
* The hostname.
*/
public void setHostname( String hostname ) {
this.hostname = hostname;
}
/**
* Configures this factory to use a single identity authenticated by the
* supplied private key. The private key should be the path to a private key
* file in OpenSSH format. Clears out the current {@link IdentityRepository}
* before adding this key.
*
* @param privateKey
* Path to a private key file
* @throws JSchException
* If the key is invalid
*/
public void setIdentityFromPrivateKey( String privateKey ) throws JSchException {
clearIdentityRepository();
jsch.addIdentity( privateKey );
}
/**
* Configures this factory to use a single identity authenticated by the
* supplied private key and pass phrase. The private key should be the path
* to a private key file in OpenSSH format. Clears out the current
* {@link IdentityRepository} before adding this key.
*
* @param privateKey
* Path to a private key file
* @param passPhrase
* Pass phrase for private key
* @throws JSchException
* If the key is invalid
*/
public void setIdentityFromPrivateKey( String privateKey, String passPhrase ) throws JSchException {
clearIdentityRepository();
jsch.addIdentity( privateKey, passPhrase );
}
/**
* Configures this factory to use a list of identities authenticated by the
* supplied private keys. The private keys should be the paths to a private
* key files in OpenSSH format. Clears out the current
* {@link IdentityRepository} before adding these keys.
*
* @param privateKeys
* A list of paths to private key files
* @throws JSchException
* If one (or more) of the keys are invalid
*/
public void setIdentitiesFromPrivateKeys( List privateKeys ) throws JSchException {
clearIdentityRepository();
for ( String privateKey : privateKeys ) {
jsch.addIdentity( privateKey );
}
}
/**
* Sets the {@link IdentityRepository} for this factory. This will replace
* any current IdentityRepository, so you should be sure to call this before
* any of the setIdentit(y|ies)Xxx
if you plan on using both.
*
* @param identityRepository
* The identity repository
*
* @see JSch#setIdentityRepository(IdentityRepository)
*/
public void setIdentityRepository( IdentityRepository identityRepository ) {
jsch.setIdentityRepository( identityRepository );
}
/**
* Sets the known hosts from the stream. Mostly useful if you distribute
* your known_hosts in the jar for your application rather than allowing
* users to manage their own known hosts.
*
* @param knownHosts
* A stream of known hosts
* @throws JSchException
* If an I/O error occurs
*
* @see JSch#setKnownHosts(InputStream)
*/
public void setKnownHosts( InputStream knownHosts ) throws JSchException {
jsch.setKnownHosts( knownHosts );
}
/**
* Sets the known hosts from a file at path knownHosts
.
*
* @param knownHosts
* The path to a known hosts file
* @throws JSchException
* If an I/O error occurs
*
* @see JSch#setKnownHosts(String)
*/
public void setKnownHosts( String knownHosts ) throws JSchException {
jsch.setKnownHosts( knownHosts );
}
/**
* Sets the {@code password} used to authenticate {@code username}. This
* mode of authentication is not recommended as it would keep the password
* in memory and if the application dies and writes a heap dump, it would be
* available. Using {@link Identity} would be better, or even using ssh
* agent support.
*
* @param password
* the password for {@code username}
*/
public void setPassword( String password ) {
this.password = password;
}
/**
* Sets the port.
*
* @param port
* The port
*/
public void setPort( int port ) {
this.port = port;
}
/**
* Sets the proxy through which all connections will be piped.
*
* @param proxy
* The proxy
*/
public void setProxy( Proxy proxy ) {
this.proxy = proxy;
}
/**
* Sets the {@code UserInfo} for use with {@code keyboard-interactive}
* authentication. This may be useful, however, setting the password
* with {@link #setPassword(String)} is likely sufficient.
*
* @param userInfo
*
* @see Keyboard
* Interactive Authentication Example
*/
public void setUserInfo( UserInfo userInfo ) {
this.userInfo = userInfo;
}
/**
* Sets the username.
*
* @param username
* The username
*/
public void setUsername( String username ) {
this.username = username;
}
@Override
public String toString() {
return (proxy == null ? "" : proxy.toString() + " ") +
"ssh://" + username + "@" + hostname + ":" + port;
}
}