/******************************************************************************* * Copyright (c) 2014 Zend Technologies Ltd. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html *******************************************************************************/ package org.zend.php.zendserver.deployment.core.tunnel; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import org.zend.php.zendserver.deployment.core.Messages; import org.zend.php.zendserver.deployment.core.targets.JSCHPubKeyDecryptor; import org.zend.sdklib.internal.target.PublicKeyNotFoundException; import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSchException; import com.jcraft.jsch.ProxyHTTP; import com.jcraft.jsch.Session; import com.jcraft.jsch.UserInfo; /** * Represents SSH tunnel which can be used e.g. for debugging connection. * It is configured using {@link SSHTunnelConfiguration} dedicated * to a particular server instance. * * @author Wojeciech Galanciak, 2014 */ public class SSHTunnel { /** * Set of possible SSH tunnel connection states. * */ public enum State { CONNECTING, CONNECTED, DISCONNECTING, DISCONNECTED, ERROR, NOT_SUPPORTED; } // connection timeout in ms private static final int TIMEOUT = 10000; private Session session; private SSHTunnelConfiguration config; public SSHTunnel(SSHTunnelConfiguration config, UserInfo userInfo) { this.config = config; } public SSHTunnel(SSHTunnelConfiguration config) { this(config, new SimpleUserInfo()); } /** * @return {@link SSHTunnelConfiguration} instance used for this SSH tunnel */ public SSHTunnelConfiguration getConfig() { return config; } /** * Establish SSH tunnel connection. Connection settings are based on * {@link SSHTunnelConfiguration} instance provided during SSH tunnel * creation. * * @return {@link State#CONNECTED} if connection was established * successfully; {@link State#CONNECTED} if tunnel is already * connected; {@link State#ERROR} if any issues occurred during * connection process * @throws TunnelException * @throws JSchException * @see State */ public State connect() throws TunnelException, JSchException { if (session == null) { initSession(); } if (!session.isConnected()) { session.connect(); configurePortForwarding(); return State.CONNECTING; } else { return State.CONNECTED; } } /** * Disconnect SSH tunnel session. */ public void disconnect() { if (isConnected()) { session.disconnect(); } } /** * @return <code>true</code> if connection is established; otherwise return * <code>false</code> */ public boolean isConnected() { return session != null ? session.isConnected() : false; } private void configurePortForwarding() throws JSchException { List<PortForwarding> entries = config.getPortForwardings(); List<PortForwarding> configured = new ArrayList<PortForwarding>(); for (PortForwarding entry : entries) { try { entry.setup(session); configured.add(entry); } catch (JSchException e) { for (PortForwarding config : configured) { config.delete(session); } throw e; } } } private void initSession() throws TunnelException, JSchException { JSch jsch = new JSch(); try { session = jsch.getSession(config.getUsername(), config.getHost(), 22); if (config.getPassword() != null) { session.setPassword(config.getPassword()); } session.setTimeout(TIMEOUT); session.setConfig("compression_level", "9"); //$NON-NLS-1$ //$NON-NLS-2$ session.setConfig("StrictHostKeyChecking", "no"); //$NON-NLS-1$ //$NON-NLS-2$ if (config.getHttpProxyHost() != null) { ProxyHTTP proxy = new ProxyHTTP(config.getHttpProxyHost(), Integer.valueOf(config.getHttpProxyPort())); session.setProxy(proxy); } if (config.getPrivateKey() != null) { JSCHPubKeyDecryptor decryptor = new JSCHPubKeyDecryptor(); String privateKey = config.getPrivateKey(); String passphrase = decryptor.getPassphase(privateKey); if (passphrase != null && passphrase.length() > 0) { jsch.addIdentity(privateKey, passphrase); } else { jsch.addIdentity(privateKey); } } } catch (PublicKeyNotFoundException e) { throw new TunnelException(MessageFormat.format( Messages.SSHTunnel_ConnectionError, config.getHost())); } } }