Package com.ericdaugherty.sshwebproxy

Source Code of com.ericdaugherty.sshwebproxy.SshConnection

/******************************************************************************
* $Source: /cvsroot/sshwebproxy/src/java/com/ericdaugherty/sshwebproxy/SshConnection.java,v $
* $Revision: 1.2 $
* $Author: edaugherty $
* $Date: 2003/11/23 00:18:10 $
******************************************************************************
* Copyright (c) 2003, Eric Daugherty (http://www.ericdaugherty.com)
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*     * Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*     * Redistributions in binary form must reproduce the above copyright
*       notice, this list of conditions and the following disclaimer in the
*       documentation and/or other materials provided with the distribution.
*     * Neither the name of the Eric Daugherty nor the names of its
*       contributors may be used to endorse or promote products derived
*       from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
* *****************************************************************************
* For current versions and more information, please visit:
* http://www.ericdaugherty.com/dev/sshwebproxy
*
* or contact the author at:
* web@ericdaugherty.com
*****************************************************************************/

package com.ericdaugherty.sshwebproxy;

import com.sshtools.j2ssh.SshClient;
import com.sshtools.j2ssh.transport.HostKeyVerification;
import com.sshtools.j2ssh.transport.TransportProtocolException;
import com.sshtools.j2ssh.transport.publickey.SshPublicKey;
import com.sshtools.j2ssh.transport.publickey.SshPrivateKeyFile;
import com.sshtools.j2ssh.transport.publickey.SshPrivateKey;
import com.sshtools.j2ssh.transport.publickey.InvalidSshKeyException;
import com.sshtools.j2ssh.authentication.PasswordAuthenticationClient;
import com.sshtools.j2ssh.authentication.AuthenticationProtocolState;
import com.sshtools.j2ssh.authentication.PublicKeyAuthenticationClient;
import com.sshtools.j2ssh.session.SessionChannelClient;
import com.sshtools.j2ssh.configuration.SshConnectionProperties;
import com.sshtools.j2ssh.configuration.ConfigurationLoader;
import com.sshtools.j2ssh.configuration.ConfigurationException;

import java.text.MessageFormat;
import java.io.IOException;
import java.util.*;
import java.net.UnknownHostException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* SshConnection represents an Ssh connection
* between the local host and a remote ssh daemon.
* A single SshConnection may contain multiple channels,
* which may be file transfer channels or shell channels.
*
* @author Eric Daugherty
*/
public class SshConnection implements SshConstants {

    //***************************************************************
    // Variables
    //***************************************************************

    /** The SSHClient instance */
    private SshClient sshClient;

    /** Information about the current connection */
    private String connectionInfo;

    /** Stores all active SshChannels. */
    private Map channelMap;

    /** The next ID to assign to a channel */
    private int nextChannelId = 0;

    /** Logger */
    private static final Log log = LogFactory.getLog( SshConnection.class );

    //***************************************************************
    // Static Initialization
    //***************************************************************

    // Initialize the SSH Library
    static
    {
        try
        {
            ConfigurationLoader.initialize( false );
        }
        catch (ConfigurationException e)
        {
            log.error( "Error configuring SSH Library: " + e, e );
            throw new RuntimeException( "Unable to initialize SSH Library: " + e, e );
        }
    }

    //***************************************************************
    // Constructors
    //***************************************************************

    /**
     * Performs common constructor logic.
     */
    private SshConnection()
    {
        channelMap = new HashMap();
    }

    /**
     * Initialize a new SshConnection with the SshClient connection.
     *
     * @param sshClient the sshClient that represents the connection.
     */
    public SshConnection( SshClient sshClient, String connectionInfo )
    {
        this();

        this.connectionInfo = connectionInfo;

        this.sshClient = sshClient;
    }

    /**
     * Create a new SshConnection to the specified location
     * with the specified username and password.
     *
     * @param host the remote host to connect to.
     * @param port the port to connect to.
     * @param username the username to login with.
     * @param password the password to login with.
     * @throws SshConnectException thrown if the connection attempt failes for any reason.
     */
    public SshConnection( String host, int port, String username, String password )
        throws SshConnectException
    {
        this();

        // Verify the parameters are not null or invalid.
        if( host == null || host.trim().length() == 0 || port < 1 ||
            username == null || username.trim().length() == 0 ||
            password == null || password.trim().length() == 0 )
        {
            throw new SshConnectException( "Missing parameter.  All parameters must be at least one character." );
        }

        connectionInfo = getConnectionInfo( host, port, username );

        if( log.isDebugEnabled() ) log.debug( connectionInfo + " - Attempting to Open Connection." );

        // Initialize the SSH library
        sshClient = new SshClient();
        sshClient.setSocketTimeout( 30000 );
        SshConnectionProperties properties = new SshConnectionProperties();
        properties.setHost( host );
        properties.setPort( port );
        properties.setPrefPublicKey("ssh-dss");

        // Connect to the host
        try
        {
            sshClient.connect(properties, new HostKeyVerificationImpl() );

            log.debug( "Connect Successful." );

            // Initialize the authentication data.
            PasswordAuthenticationClient pwd = new PasswordAuthenticationClient();
            pwd.setUsername(username);
            pwd.setPassword(password);

            // Authenticate
            int result = sshClient.authenticate(pwd);
            if( result != AuthenticationProtocolState.COMPLETE )
            {
                throw new SshConnectException( "Authentication Error.  Invalid username or password." );
            }

            log.debug( "Authentication Successful." );
        }
        catch( UnknownHostException unknownHostException )
        {
            throw new SshConnectException( "Unable to connect.  Unknown host." );
        }
        catch( IOException ioException )
        {
            log.warn( "IOException occured in SshConnection constructor.  " + ioException, ioException );
            throw new SshConnectException( "Unable to connect to host." );
        }

        // Success!
        if( log.isInfoEnabled() ) log.info( connectionInfo + " - Connection opened successfully." );
    }

    /**
     * Create a new SshConnection to the specified location
     * with the specified username and key.
     *
     * @param host the remote host to connect to.
     * @param port the port to connect to.
     * @param username the username to login with.
     * @param key the SSH Key as a byte array.
     * @param keyPassPhrase the passPharse for the key (optional)
     * @throws SshConnectException thrown if the connection attempt failes for any reason.
     */
     public SshConnection( String host, int port, String username, byte[] key, String keyPassPhrase )
             throws SshConnectException
    {
        this();

        // Verify the parameters are not null or invalid.
        if( host == null || host.trim().length() == 0 || port < 1 ||
            username == null || username.trim().length() == 0 ||
            key == null )
        {
            throw new SshConnectException( "Missing parameter.  All parameters must be at least one character." );
        }

        connectionInfo = getConnectionInfo( host, port, username );

        if( log.isDebugEnabled() ) log.debug( connectionInfo + " - Attempting to Open Connection." );

        // Initialize the SSH library
        sshClient = new SshClient();
        sshClient.setSocketTimeout( 30000 );
        SshConnectionProperties properties = new SshConnectionProperties();
        properties.setHost( host );
        properties.setPort( port );

        // Connect to the host
        try
        {
            sshClient.connect(properties, new HostKeyVerificationImpl() );

            log.debug( "Connect Successful." );

            // Initialize the authentication data.
            PublicKeyAuthenticationClient publicKeyAuth = new PublicKeyAuthenticationClient();

            publicKeyAuth.setUsername(username);

            SshPrivateKeyFile file = SshPrivateKeyFile.parse( key );
            SshPrivateKey privateKey = file.toPrivateKey( keyPassPhrase );
            publicKeyAuth.setKey( privateKey );

            // Authenticate
            int result = sshClient.authenticate( publicKeyAuth );
            if( result != AuthenticationProtocolState.COMPLETE )
            {
                throw new SshConnectException( "Authentication Error.  Invalid username or password." );
            }

            log.debug( "Authentication Successful." );
        }
        catch( InvalidSshKeyException invalidSshKeyException )
        {
            throw new SshConnectException( "Unable to connect.  Invalid SSH Key.  " + invalidSshKeyException.getMessage() );
        }
        catch( UnknownHostException unknownHostException )
        {
            throw new SshConnectException( "Unable to connect.  Unknown host." );
        }
        catch( IOException ioException )
        {
            log.warn( "IOException occured in SshConnection constructor.  " + ioException, ioException );
            throw new SshConnectException( "Unable to connect to host." );
        }

        // Success!
        if( log.isInfoEnabled() ) log.info( connectionInfo + " - Connection opened successfully." );
    }
    //***************************************************************
    // Parameter Access Methods
    //***************************************************************

    /**
     * Returns information about this connection.  The information
     * consists of the username, the host, and the port.  The result
     * is formatted as: username@host:port
     *
     * @return formated string: username@host:port
     */
    public String getConnectionInfo()
    {
        return connectionInfo;
    }

    /**
     * Helper method to return the connection info.
     *
     * @param host
     * @param port
     * @param username
     * @return a propertly formatted connection info string.
     */
    public static String getConnectionInfo( String host, String port, String username )
    {
        return MessageFormat.format( "{0}@{1}:{2}", new String[] { username.trim(), host.trim(), port.trim() } );
    }

    /**
     * Helper method to return the connection info.
     *
     * @param host
     * @param port
     * @param username
     * @return a propertly formatted connection info string.
     */
    public static String getConnectionInfo( String host, int port, String username )
    {
        return getConnectionInfo( host, String.valueOf( port ), username );
    }

    //***************************************************************
    // Public Methods
    //***************************************************************

    /**
     * Returns true if this SshConnection is open.
     *
     * @return true if it is open.
     */
    public boolean isOpen()
    {
        return sshClient.isConnected();
    }

    /**
     * Closes all open channels and the current SshConnection.
     */
    public void close()
    {
        if( log.isInfoEnabled() ) log.info( connectionInfo + " - Closing Connection." );

        Iterator shellChannels = channelMap.values().iterator();
        SshChannel shellChannel;
        while( shellChannels.hasNext() )
        {
            shellChannel = (SshChannel) shellChannels.next();
            shellChannel.close();
        }

        channelMap.clear();

        sshClient.disconnect();
    }

    /**
     * Returns the requested channel.
     *
     * @param channelId the channel's unique id.
     * @return the requested channel, or null if it does not exist.
     */
    public SshChannel getChannel( String channelId )
    {
        return (SshChannel) channelMap.get( channelId );
    }

    /**
     * Returns all channels
     */
    public Collection getChannels()
    {
        return channelMap.values();
    }

    /**
     * Open a new Shell Channel for this connection.
     *
     * @return a newly opened ShellChannel
     * @throws SshConnectException if the channel could not be opened.
     */
    public ShellChannel openShellChannel() throws SshConnectException
    {
        if( log.isInfoEnabled() ) log.info( connectionInfo + " - Opening new ShellChannel" );

        try
        {
            SessionChannelClient sessionChannelClient = sshClient.openSessionChannel();
            ShellChannel shellChannel = new VT100ShellChannel( this, sessionChannelClient );

            // Generate a channelId for the channel and add it to the local map.
            String channelId = String.valueOf( nextChannelId++ );
            shellChannel.setChannelId( channelId );
            channelMap.put( channelId, shellChannel );

            return shellChannel;
        }
        catch (IOException ioException) {
            log.warn( "openShellChannel failed, unable to open Session Channel: " + ioException, ioException );
            throw new SshConnectException( "Unable to open SessionChannel." );
        }
    }

    /**
     * Open a new File Channel for this connection.
     *
     * @return a newly opened FileChannel
     * @throws SshConnectException if the channel could not be opened.
     */
    public FileChannel openFileChannel() throws SshConnectException
    {
        if( log.isInfoEnabled() ) log.info( connectionInfo + " - Opening new FileChannel" );

        FileChannel fileChannel = new FileChannel( this, sshClient );

        // Generate a channelId for the channel and add it to the local map.
        String channelId = String.valueOf( nextChannelId++ );
        fileChannel.setChannelId( channelId );
        channelMap.put( channelId, fileChannel );

        return fileChannel;
    }

    /**
     * Returns the requested channel.
     *
     * @param channelId the channel's unique id.
     * @return the requested channel, or null if it does not exist.
     */
    public ShellChannel getShellChannel( String channelId )
    {
        SshChannel channel = (SshChannel) channelMap.get( channelId );

        // Return null if it does not exist or is the wrong type of channel.
        if( channel == null || !( channel instanceof ShellChannel ) )
        {
            return null;
        }

        return (ShellChannel) channel;
    }

    /**
     * Returns a collection of all ShellChannels associated with this
     * connection.
     *
     * @return will never be null.
     */
    public Collection getShellChannels()
    {
        ArrayList shellChannels = new ArrayList();
        Iterator channelIterator = channelMap.values().iterator();
        SshChannel sshChannel;
        while( channelIterator.hasNext() )
        {
            sshChannel = (SshChannel) channelIterator.next();
            if( CHANNEL_TYPE_SHELL.equals( sshChannel.getChannelType() ) )
            {
                shellChannels.add( sshChannel );
            }

        }

        return shellChannels;
    }

    /**
     * Returns the requested channel.
     *
     * @param channelId the channel's unique id.
     * @return the requested channel, or null if it does not exist.
     */
    public FileChannel getFileChannel( String channelId )
    {
        SshChannel channel = (SshChannel) channelMap.get( channelId );

        // Return null if it does not exist or is the wrong type of channel.
        if( channel == null || !( channel instanceof FileChannel ) )
        {
            return null;
        }

        return (FileChannel) channel;
    }

    /**
     * Close a specfic channel.  This calls channel.close()
     * and removes it from the channel list.
     *
     * @param channelId the channel to remove.
     */
    public void closeChannel( String channelId )
    {
        SshChannel sshChannel = getChannel( channelId );
        if( sshChannel != null )
        {
            sshChannel.close();
            channelMap.remove( sshChannel.getChannelId() );
        }
    }

    /**
     * Close a specfic channel.  This calls channel.close()
     * and removes it from the channel list.
     *
     * @param sshChannel the channel to remove.
     */
    public void closeChannel( SshChannel sshChannel )
    {
        sshChannel.close();
        channelMap.remove( sshChannel.getChannelId() );
    }

    //***************************************************************
    // Object Methods
    //***************************************************************

    /**
     * Return a string representation of this connection.
     * @return
     */
    public String toString() {
        String[] args = new String[] { getConnectionInfo(), String.valueOf( sshClient.getActiveChannelCount() ) };
        return MessageFormat.format( "Connected to {0} with {1} open channels.", args );
    }

    //***************************************************************
    // Inner Classes
    //***************************************************************

    /**
     * Handles the HostKeyVerification.  Current implementation accepts
     * all keys.
     *
     * @author Eric Daugherty
     */
    private class HostKeyVerificationImpl implements HostKeyVerification
    {
        /**
         * Determines if the host key should be accepted.
         * @param string
         * @param sshPublicKey
         * @return
         * @throws com.sshtools.j2ssh.transport.TransportProtocolException
         */
        public boolean verifyHost(String string, SshPublicKey sshPublicKey) throws TransportProtocolException {
            //TODO: Add real logic here to handle Host Key Validation.
            log.debug( "Verifying Host: " + string );
            return true;
        }
    }
}
TOP

Related Classes of com.ericdaugherty.sshwebproxy.SshConnection

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.