提交 1eb324dc 编写于 作者: S serge-rider

#2202 SSH model refactoring. SSHJ implementation stub

上级 21422c7e
......@@ -758,6 +758,7 @@ public class CoreMessages extends NLS {
public static String model_ssh_configurator_label_port;
public static String model_ssh_configurator_label_private_key;
public static String model_ssh_configurator_label_user_name;
public static String model_ssh_configurator_label_implementation;
public static String model_ssh_configurator_label_local_port;
public static String model_ssh_configurator_label_local_port_description;
public static String model_ssh_configurator_label_keep_alive;
......
......@@ -752,6 +752,7 @@ model_ssh_configurator_label_password = Password
model_ssh_configurator_label_port = Port
model_ssh_configurator_label_private_key = Private Key
model_ssh_configurator_label_user_name = User Name
model_ssh_configurator_label_implementation = Implementation
model_ssh_configurator_label_local_port = Local port
model_ssh_configurator_label_local_port_description = Local port for tunnel. If set to <=0 then random free port (>10000) will be acquired
model_ssh_configurator_label_keep_alive = Keep-Alive interval (ms)
......
......@@ -25,6 +25,7 @@ import org.eclipse.swt.widgets.*;
import org.jkiss.dbeaver.core.CoreMessages;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.model.impl.net.SSHConstants;
import org.jkiss.dbeaver.model.impl.net.SSHImplType;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.ui.IObjectPropertyConfigurator;
import org.jkiss.dbeaver.ui.UIUtils;
......@@ -48,6 +49,7 @@ public class SSHTunnelConfiguratorUI implements IObjectPropertyConfigurator<DBWH
private Text passwordText;
private Button savePasswordCheckbox;
private Label privateKeyLabel;
private Combo tunnelImplCombo;
private Spinner localPortSpinner;
private Spinner keepAliveText;
private Spinner tunnelTimeout;
......@@ -94,6 +96,11 @@ public class SSHTunnelConfiguratorUI implements IObjectPropertyConfigurator<DBWH
{
Group advancedGroup = UIUtils.createControlGroup(composite, CoreMessages.model_ssh_configurator_group_advanced, 2, GridData.FILL_HORIZONTAL, SWT.DEFAULT);
tunnelImplCombo = UIUtils.createLabelCombo(advancedGroup, CoreMessages.model_ssh_configurator_label_implementation, SWT.DROP_DOWN | SWT.READ_ONLY);
tunnelImplCombo.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_BEGINNING));
for (SSHImplType it : SSHImplType.values()) {
tunnelImplCombo.add(it.getLabel());
}
localPortSpinner = UIUtils.createLabelSpinner(advancedGroup, CoreMessages.model_ssh_configurator_label_local_port, 0, Integer.MIN_VALUE, Integer.MAX_VALUE);
localPortSpinner.setToolTipText(CoreMessages.model_ssh_configurator_label_local_port_description);
keepAliveText = UIUtils.createLabelSpinner(advancedGroup, CoreMessages.model_ssh_configurator_label_keep_alive, 0, 0, Integer.MAX_VALUE);
......@@ -129,6 +136,18 @@ public class SSHTunnelConfiguratorUI implements IObjectPropertyConfigurator<DBWH
passwordText.setText(CommonUtils.notEmpty(configuration.getPassword()));
savePasswordCheckbox.setSelection(configuration.isSavePassword());
String implType = configuration.getProperties().get(SSHConstants.PROP_IMPLEMENTATION);
if (CommonUtils.isEmpty(implType)) {
tunnelImplCombo.select(0);
} else {
try {
SSHImplType it = SSHImplType.getById(implType);
tunnelImplCombo.setText(it.getLabel());
} catch (IllegalArgumentException e) {
tunnelImplCombo.select(0);
}
}
String lpString = configuration.getProperties().get(SSHConstants.PROP_LOCAL_PORT);
if (!CommonUtils.isEmpty(lpString)) {
localPortSpinner.setSelection(Integer.parseInt(lpString));
......@@ -162,6 +181,13 @@ public class SSHTunnelConfiguratorUI implements IObjectPropertyConfigurator<DBWH
configuration.setPassword(passwordText.getText());
configuration.setSavePassword(savePasswordCheckbox.getSelection());
String implLabel = tunnelImplCombo.getText();
for (SSHImplType it : SSHImplType.values()) {
if (it.getLabel().equals(implLabel)) {
properties.put(SSHConstants.PROP_IMPLEMENTATION, it.getId());
break;
}
}
int localPort = localPortSpinner.getSelection();
if (localPort <= 0) {
properties.remove(SSHConstants.PROP_LOCAL_PORT);
......@@ -197,12 +223,7 @@ public class SSHTunnelConfiguratorUI implements IObjectPropertyConfigurator<DBWH
// }
pwdLabel.setText(isPassword ? CoreMessages.model_ssh_configurator_label_password : CoreMessages.model_ssh_configurator_label_passphrase);
DBeaverUI.asyncExec(new Runnable() {
@Override
public void run() {
hostText.getParent().getParent().layout(true, true);
}
});
DBeaverUI.asyncExec(() -> hostText.getParent().getParent().layout(true, true));
}
@Override
......
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jkiss.dbeaver.model.impl.net;
/**
* SSH implementation enum
*/
public enum SSHImplType {
JSCH("jsch", "JSch", SSHImplementationJsch.class),
SSHJ("sshj", "SSHJ", SSHImplementationSshj.class);
private String id;
private String label;
private Class<? extends SSHImplementation> implClass;
SSHImplType(String id, String label, Class<? extends SSHImplementation> implClass) {
this.id = id;
this.label = label;
this.implClass = implClass;
}
public String getId() {
return id;
}
public String getLabel() {
return label;
}
public Class<? extends SSHImplementation> getImplClass() {
return implClass;
}
public static SSHImplType getById(String id) throws IllegalArgumentException {
for (SSHImplType it : values()) {
if (it.getId().equals(id)) {
return it;
}
}
throw new IllegalArgumentException("Bad SSH impl: " + id);
}
}
\ No newline at end of file
......@@ -29,10 +29,13 @@ import java.io.IOException;
*/
public interface SSHImplementation {
DBPConnectionConfiguration startPortForward(DBRProgressMonitor monitor, DBPPlatform platform, DBWHandlerConfiguration configuration, DBPConnectionConfiguration connectionInfo)
DBPConnectionConfiguration initTunnel(DBRProgressMonitor monitor, DBPPlatform platform, DBWHandlerConfiguration configuration, DBPConnectionConfiguration connectionInfo)
throws DBException, IOException;
void stopPortForward(DBRProgressMonitor monitor)
void invalidateTunnel(DBRProgressMonitor monitor)
throws DBException, IOException;
void closeTunnel(DBRProgressMonitor monitor)
throws DBException, IOException;
}
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jkiss.dbeaver.model.impl.net;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.app.DBPPlatform;
import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.utils.CommonUtils;
import java.io.File;
import java.io.IOException;
import java.util.Map;
/**
* SSH tunnel
*/
public abstract class SSHImplementationAbstract implements SSHImplementation {
private static final Log log = Log.getLog(SSHImplementationAbstract.class);
// Saved config - used for tunnel invalidate
private transient int savedLocalPort;
protected transient DBWHandlerConfiguration savedConfiguration;
protected transient DBPConnectionConfiguration savedConnectionInfo;
@Override
public DBPConnectionConfiguration initTunnel(DBRProgressMonitor monitor, DBPPlatform platform, DBWHandlerConfiguration configuration, DBPConnectionConfiguration connectionInfo)
throws DBException, IOException
{
String dbPortString = connectionInfo.getHostPort();
if (CommonUtils.isEmpty(dbPortString)) {
dbPortString = configuration.getDriver().getDefaultPort();
if (CommonUtils.isEmpty(dbPortString)) {
throw new DBException("Database port not specified and no default port number for driver '" + configuration.getDriver().getName() + "'");
}
}
String dbHost = connectionInfo.getHostName();
Map<String,String> properties = configuration.getProperties();
String sshAuthType = properties.get(SSHConstants.PROP_AUTH_TYPE);
String sshHost = properties.get(SSHConstants.PROP_HOST);
String sshPort = properties.get(SSHConstants.PROP_PORT);
String sshLocalPort = properties.get(SSHConstants.PROP_LOCAL_PORT);
String sshUser = configuration.getUserName();
String aliveInterval = properties.get(SSHConstants.PROP_ALIVE_INTERVAL);
String connectTimeoutString = properties.get(SSHConstants.PROP_CONNECT_TIMEOUT);
//String aliveCount = properties.get(SSHConstants.PROP_ALIVE_COUNT);
if (CommonUtils.isEmpty(sshHost)) {
throw new DBException("SSH host not specified");
}
if (CommonUtils.isEmpty(sshPort)) {
throw new DBException("SSH port not specified");
}
if (CommonUtils.isEmpty(sshUser)) {
throw new DBException("SSH user not specified");
}
int sshPortNum;
try {
sshPortNum = Integer.parseInt(sshPort);
}
catch (NumberFormatException e) {
throw new DBException("Invalid SSH port: " + sshPort);
}
SSHConstants.AuthType authType = SSHConstants.AuthType.PASSWORD;
if (sshAuthType != null) {
authType = SSHConstants.AuthType.valueOf(sshAuthType);
}
File privKeyFile = null;
String privKeyPath = properties.get(SSHConstants.PROP_KEY_PATH);
if (authType == SSHConstants.AuthType.PUBLIC_KEY) {
if (CommonUtils.isEmpty(privKeyPath)) {
throw new DBException("Private key path is empty");
}
privKeyFile = new File(privKeyPath);
if (!privKeyFile.exists()) {
throw new DBException("Private key file '" + privKeyFile.getAbsolutePath() + "' doesn't exist");
}
}
int connectTimeout;
try {
connectTimeout = Integer.parseInt(connectTimeoutString);
}
catch (NumberFormatException e) {
connectTimeout = SSHConstants.DEFAULT_CONNECT_TIMEOUT;
}
monitor.subTask("Initiating tunnel at '" + sshHost + "'");
int dbPort;
try {
dbPort = Integer.parseInt(dbPortString);
} catch (NumberFormatException e) {
throw new DBException("Bad database port number: " + dbPortString);
}
int localPort = savedLocalPort;
if (platform != null) {
localPort = SSHUtils.findFreePort(platform);
}
if (!CommonUtils.isEmpty(sshLocalPort)) {
try {
int forceLocalPort = Integer.parseInt(sshLocalPort);
if (forceLocalPort > 0) {
localPort = forceLocalPort;
}
} catch (NumberFormatException e) {
log.warn("Bad local port specified", e);
}
}
setupTunnel(monitor, configuration, dbHost, sshHost, sshUser, aliveInterval, sshPortNum, privKeyFile, connectTimeout, dbPort, localPort);
savedLocalPort = localPort;
savedConfiguration = configuration;
savedConnectionInfo = connectionInfo;
connectionInfo = new DBPConnectionConfiguration(connectionInfo);
String newPortValue = String.valueOf(localPort);
// Replace database host/port and URL - let's use localhost
connectionInfo.setHostName(SSHConstants.LOCALHOST_NAME);
connectionInfo.setHostPort(newPortValue);
String newURL = configuration.getDriver().getDataSourceProvider().getConnectionURL(
configuration.getDriver(),
connectionInfo);
connectionInfo.setUrl(newURL);
return connectionInfo;
}
protected abstract void setupTunnel(DBRProgressMonitor monitor, DBWHandlerConfiguration configuration, String dbHost, String sshHost, String sshUser, String aliveInterval, int sshPortNum, File privKeyFile, int connectTimeout, int dbPort, int localPort) throws DBException, IOException;
}
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jkiss.dbeaver.model.impl.net;
import com.jcraft.jsch.*;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.utils.RuntimeUtils;
import org.jkiss.utils.CommonUtils;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
/**
* SSH tunnel
*/
public class SSHImplementationJsch extends SSHImplementationAbstract {
private static final Log log = Log.getLog(SSHImplementationJsch.class);
private static transient JSch jsch;
private transient Session session;
@Override
protected void setupTunnel(DBRProgressMonitor monitor, DBWHandlerConfiguration configuration, String dbHost, String sshHost, String sshUser, String aliveInterval, int sshPortNum, File privKeyFile, int connectTimeout, int dbPort, int localPort) throws DBException, IOException {
UserInfo ui = new UIUserInfo(configuration);
try {
if (jsch == null) {
jsch = new JSch();
JSch.setLogger(new LoggerProxy());
}
if (privKeyFile != null) {
if (!CommonUtils.isEmpty(ui.getPassphrase())) {
jsch.addIdentity(privKeyFile.getAbsolutePath(), ui.getPassphrase());
} else {
jsch.addIdentity(privKeyFile.getAbsolutePath());
}
}
log.debug("Instantiate SSH tunnel");
session = jsch.getSession(sshUser, sshHost, sshPortNum);
session.setConfig("StrictHostKeyChecking", "no");
//session.setConfig("PreferredAuthentications", "password,publickey,keyboard-interactive");
session.setConfig("PreferredAuthentications",
privKeyFile != null ? "publickey" : "password");
session.setConfig("ConnectTimeout", String.valueOf(connectTimeout));
session.setUserInfo(ui);
if (!CommonUtils.isEmpty(aliveInterval)) {
session.setServerAliveInterval(Integer.parseInt(aliveInterval));
}
log.debug("Connect to tunnel host");
session.connect(connectTimeout);
try {
session.setPortForwardingL(localPort, dbHost, dbPort);
} catch (JSchException e) {
closeTunnel(monitor);
throw e;
}
} catch (JSchException e) {
throw new DBException("Cannot establish tunnel", e);
}
}
@Override
public void closeTunnel(DBRProgressMonitor monitor) throws DBException, IOException {
if (session != null) {
RuntimeUtils.runTask(monitor1 -> {
try {
session.disconnect();
} catch (Exception e) {
throw new InvocationTargetException(e);
}
}, "Close SSH session", 1000);
session = null;
}
}
@Override
public void invalidateTunnel(DBRProgressMonitor monitor) throws DBException, IOException {
boolean isAlive = session != null && session.isConnected();
if (isAlive) {
try {
session.sendKeepAliveMsg();
} catch (Exception e) {
isAlive = false;
}
}
if (!isAlive) {
closeTunnel(monitor);
initTunnel(monitor, null, savedConfiguration, savedConnectionInfo);
}
}
private class UIUserInfo implements UserInfo {
DBWHandlerConfiguration configuration;
private UIUserInfo(DBWHandlerConfiguration configuration)
{
this.configuration = configuration;
}
@Override
public String getPassphrase()
{
return configuration.getPassword();
}
@Override
public String getPassword()
{
return configuration.getPassword();
}
@Override
public boolean promptPassword(String message)
{
return true;
}
@Override
public boolean promptPassphrase(String message)
{
return true;
}
@Override
public boolean promptYesNo(String message)
{
return false;
}
@Override
public void showMessage(String message)
{
log.info(message);
}
}
private class LoggerProxy implements Logger {
@Override
public boolean isEnabled(int level) {
return true;
}
@Override
public void log(int level, String message) {
String levelStr;
switch (level) {
case INFO: levelStr = "INFO"; break;
case WARN: levelStr = "WARN"; break;
case ERROR: levelStr = "ERROR"; break;
case FATAL: levelStr = "FATAL"; break;
case DEBUG:
default:
levelStr = "DEBUG";
break;
}
log.debug("SSH " + levelStr + ": " + message);
}
}
}
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jkiss.dbeaver.model.impl.net;
import com.jcraft.jsch.*;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.utils.RuntimeUtils;
import org.jkiss.utils.CommonUtils;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
/**
* SSHJ tunnel
*/
public class SSHImplementationSshj extends SSHImplementationAbstract {
private static final Log log = Log.getLog(SSHImplementationSshj.class);
private static transient JSch jsch;
private transient Session session;
@Override
protected void setupTunnel(DBRProgressMonitor monitor, DBWHandlerConfiguration configuration, String dbHost, String sshHost, String sshUser, String aliveInterval, int sshPortNum, File privKeyFile, int connectTimeout, int dbPort, int localPort) throws DBException, IOException {
UserInfo ui = new UIUserInfo(configuration);
try {
if (jsch == null) {
jsch = new JSch();
JSch.setLogger(new LoggerProxy());
}
if (privKeyFile != null) {
if (!CommonUtils.isEmpty(ui.getPassphrase())) {
jsch.addIdentity(privKeyFile.getAbsolutePath(), ui.getPassphrase());
} else {
jsch.addIdentity(privKeyFile.getAbsolutePath());
}
}
log.debug("Instantiate SSH tunnel");
session = jsch.getSession(sshUser, sshHost, sshPortNum);
session.setConfig("StrictHostKeyChecking", "no");
//session.setConfig("PreferredAuthentications", "password,publickey,keyboard-interactive");
session.setConfig("PreferredAuthentications",
privKeyFile != null ? "publickey" : "password");
session.setConfig("ConnectTimeout", String.valueOf(connectTimeout));
session.setUserInfo(ui);
if (!CommonUtils.isEmpty(aliveInterval)) {
session.setServerAliveInterval(Integer.parseInt(aliveInterval));
}
log.debug("Connect to tunnel host");
session.connect(connectTimeout);
try {
session.setPortForwardingL(localPort, dbHost, dbPort);
} catch (JSchException e) {
closeTunnel(monitor);
throw e;
}
} catch (JSchException e) {
throw new DBException("Cannot establish tunnel", e);
}
}
@Override
public void closeTunnel(DBRProgressMonitor monitor) throws DBException, IOException {
if (session != null) {
RuntimeUtils.runTask(monitor1 -> {
try {
session.disconnect();
} catch (Exception e) {
throw new InvocationTargetException(e);
}
}, "Close SSH session", 1000);
session = null;
}
}
@Override
public void invalidateTunnel(DBRProgressMonitor monitor) throws DBException, IOException {
boolean isAlive = session != null && session.isConnected();
if (isAlive) {
try {
session.sendKeepAliveMsg();
} catch (Exception e) {
isAlive = false;
}
}
if (!isAlive) {
closeTunnel(monitor);
initTunnel(monitor, null, savedConfiguration, savedConnectionInfo);
}
}
private class UIUserInfo implements UserInfo {
DBWHandlerConfiguration configuration;
private UIUserInfo(DBWHandlerConfiguration configuration)
{
this.configuration = configuration;
}
@Override
public String getPassphrase()
{
return configuration.getPassword();
}
@Override
public String getPassword()
{
return configuration.getPassword();
}
@Override
public boolean promptPassword(String message)
{
return true;
}
@Override
public boolean promptPassphrase(String message)
{
return true;
}
@Override
public boolean promptYesNo(String message)
{
return false;
}
@Override
public void showMessage(String message)
{
log.info(message);
}
}
private class LoggerProxy implements Logger {
@Override
public boolean isEnabled(int level) {
return true;
}
@Override
public void log(int level, String message) {
String levelStr;
switch (level) {
case INFO: levelStr = "INFO"; break;
case WARN: levelStr = "WARN"; break;
case ERROR: levelStr = "ERROR"; break;
case FATAL: levelStr = "FATAL"; break;
case DEBUG:
default:
levelStr = "DEBUG";
break;
}
log.debug("SSH " + levelStr + ": " + message);
}
}
}
......@@ -16,7 +16,6 @@
*/
package org.jkiss.dbeaver.model.impl.net;
import com.jcraft.jsch.*;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.app.DBPPlatform;
......@@ -24,12 +23,9 @@ import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.net.DBWTunnel;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.utils.RuntimeUtils;
import org.jkiss.utils.CommonUtils;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
/**
......@@ -39,160 +35,36 @@ public class SSHTunnelImpl implements DBWTunnel {
private static final Log log = Log.getLog(SSHTunnelImpl.class);
private static transient JSch jsch;
private transient Session session;
// Saved config - used for tunnel invalidate
private transient int savedLocalPort;
private transient DBWHandlerConfiguration savedConfiguration;
private transient DBPConnectionConfiguration savedConnectionInfo;
private SSHImplementation implementation;
@Override
public DBPConnectionConfiguration initializeTunnel(DBRProgressMonitor monitor, DBPPlatform platform, DBWHandlerConfiguration configuration, DBPConnectionConfiguration connectionInfo)
throws DBException, IOException
{
String dbPortString = connectionInfo.getHostPort();
if (CommonUtils.isEmpty(dbPortString)) {
dbPortString = configuration.getDriver().getDefaultPort();
if (CommonUtils.isEmpty(dbPortString)) {
throw new DBException("Database port not specified and no default port number for driver '" + configuration.getDriver().getName() + "'");
}
}
String dbHost = connectionInfo.getHostName();
Map<String,String> properties = configuration.getProperties();
String sshAuthType = properties.get(SSHConstants.PROP_AUTH_TYPE);
String sshHost = properties.get(SSHConstants.PROP_HOST);
String sshPort = properties.get(SSHConstants.PROP_PORT);
String sshLocalPort = properties.get(SSHConstants.PROP_LOCAL_PORT);
String sshUser = configuration.getUserName();
String aliveInterval = properties.get(SSHConstants.PROP_ALIVE_INTERVAL);
String connectTimeoutString = properties.get(SSHConstants.PROP_CONNECT_TIMEOUT);
//String aliveCount = properties.get(SSHConstants.PROP_ALIVE_COUNT);
if (CommonUtils.isEmpty(sshHost)) {
throw new DBException("SSH host not specified");
}
if (CommonUtils.isEmpty(sshPort)) {
throw new DBException("SSH port not specified");
}
if (CommonUtils.isEmpty(sshUser)) {
throw new DBException("SSH user not specified");
}
int sshPortNum;
try {
sshPortNum = Integer.parseInt(sshPort);
}
catch (NumberFormatException e) {
throw new DBException("Invalid SSH port: " + sshPort);
}
SSHConstants.AuthType authType = SSHConstants.AuthType.PASSWORD;
if (sshAuthType != null) {
authType = SSHConstants.AuthType.valueOf(sshAuthType);
}
File privKeyFile = null;
String privKeyPath = properties.get(SSHConstants.PROP_KEY_PATH);
if (authType == SSHConstants.AuthType.PUBLIC_KEY) {
if (CommonUtils.isEmpty(privKeyPath)) {
throw new DBException("Private key path is empty");
}
privKeyFile = new File(privKeyPath);
if (!privKeyFile.exists()) {
throw new DBException("Private key file '" + privKeyFile.getAbsolutePath() + "' doesn't exist");
}
}
int connectTimeout;
try {
connectTimeout = Integer.parseInt(connectTimeoutString);
}
catch (NumberFormatException e) {
connectTimeout = SSHConstants.DEFAULT_CONNECT_TIMEOUT;
}
monitor.subTask("Initiating tunnel at '" + sshHost + "'");
UserInfo ui = new UIUserInfo(configuration);
int dbPort;
try {
dbPort = Integer.parseInt(dbPortString);
} catch (NumberFormatException e) {
throw new DBException("Bad database port number: " + dbPortString);
}
int localPort = savedLocalPort;
if (platform != null) {
localPort = SSHUtils.findFreePort(platform);
}
if (!CommonUtils.isEmpty(sshLocalPort)) {
String implId = properties.get(SSHConstants.PROP_IMPLEMENTATION);
SSHImplType implType = SSHImplType.JSCH;
if (!CommonUtils.isEmpty(implId)) {
try {
int forceLocalPort = Integer.parseInt(sshLocalPort);
if (forceLocalPort > 0) {
localPort = forceLocalPort;
}
} catch (NumberFormatException e) {
log.warn("Bad local port specified", e);
implType = SSHImplType.getById(implId);
} catch (IllegalArgumentException e) {
log.error(e);
}
}
try {
if (jsch == null) {
jsch = new JSch();
JSch.setLogger(new LoggerProxy());
}
if (privKeyFile != null) {
if (!CommonUtils.isEmpty(ui.getPassphrase())) {
jsch.addIdentity(privKeyFile.getAbsolutePath(), ui.getPassphrase());
} else {
jsch.addIdentity(privKeyFile.getAbsolutePath());
}
}
log.debug("Instantiate SSH tunnel");
session = jsch.getSession(sshUser, sshHost, sshPortNum);
session.setConfig("StrictHostKeyChecking", "no");
//session.setConfig("PreferredAuthentications", "password,publickey,keyboard-interactive");
session.setConfig("PreferredAuthentications",
privKeyFile != null ? "publickey" : "password");
session.setConfig("ConnectTimeout", String.valueOf(connectTimeout));
session.setUserInfo(ui);
if (!CommonUtils.isEmpty(aliveInterval)) {
session.setServerAliveInterval(Integer.parseInt(aliveInterval));
}
log.debug("Connect to tunnel host");
session.connect(connectTimeout);
try {
session.setPortForwardingL(localPort, dbHost, dbPort);
} catch (JSchException e) {
closeTunnel(monitor);
throw e;
}
} catch (JSchException e) {
throw new DBException("Cannot establish tunnel", e);
implementation = implType.getImplClass().newInstance();
} catch (Throwable e) {
throw new DBException("Can't create SSH tunnel implementation", e);
}
savedLocalPort = localPort;
savedConfiguration = configuration;
savedConnectionInfo = connectionInfo;
connectionInfo = new DBPConnectionConfiguration(connectionInfo);
String newPortValue = String.valueOf(localPort);
// Replace database host/port and URL - let's use localhost
connectionInfo.setHostName(SSHConstants.LOCALHOST_NAME);
connectionInfo.setHostPort(newPortValue);
String newURL = configuration.getDriver().getDataSourceProvider().getConnectionURL(
configuration.getDriver(),
connectionInfo);
connectionInfo.setUrl(newURL);
return connectionInfo;
return implementation.initTunnel(monitor, platform, configuration, connectionInfo);
}
@Override
public void closeTunnel(DBRProgressMonitor monitor) throws DBException, IOException
{
if (session != null) {
RuntimeUtils.runTask(monitor1 -> {
try {
session.disconnect();
} catch (Exception e) {
throw new InvocationTargetException(e);
}
}, "Close SSH session", 1000);
session = null;
if (implementation != null) {
implementation.closeTunnel(monitor);
implementation = null;
}
}
......@@ -224,85 +96,9 @@ public class SSHTunnelImpl implements DBWTunnel {
@Override
public void invalidateHandler(DBRProgressMonitor monitor) throws DBException, IOException {
boolean isAlive = session != null && session.isConnected();
if (isAlive) {
try {
session.sendKeepAliveMsg();
} catch (Exception e) {
isAlive = false;
}
}
if (!isAlive) {
closeTunnel(monitor);
initializeTunnel(monitor, null, savedConfiguration, savedConnectionInfo);
if (implementation != null) {
implementation.invalidateTunnel(monitor);
}
}
private class UIUserInfo implements UserInfo {
DBWHandlerConfiguration configuration;
private UIUserInfo(DBWHandlerConfiguration configuration)
{
this.configuration = configuration;
}
@Override
public String getPassphrase()
{
return configuration.getPassword();
}
@Override
public String getPassword()
{
return configuration.getPassword();
}
@Override
public boolean promptPassword(String message)
{
return true;
}
@Override
public boolean promptPassphrase(String message)
{
return true;
}
@Override
public boolean promptYesNo(String message)
{
return false;
}
@Override
public void showMessage(String message)
{
log.info(message);
}
}
private class LoggerProxy implements Logger {
@Override
public boolean isEnabled(int level) {
return true;
}
@Override
public void log(int level, String message) {
String levelStr;
switch (level) {
case INFO: levelStr = "INFO"; break;
case WARN: levelStr = "WARN"; break;
case ERROR: levelStr = "ERROR"; break;
case FATAL: levelStr = "FATAL"; break;
case DEBUG:
default:
levelStr = "DEBUG";
break;
}
log.debug("SSH " + levelStr + ": " + message);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册