Skip to content
This repository has been archived by the owner on Jul 11, 2022. It is now read-only.

Commit

Permalink
BZ 1090462 - prototype to see if I can get key fingerprints authentic…
Browse files Browse the repository at this point in the history
…ated and stored in a known_hosts file
  • Loading branch information
jmazzitelli committed Apr 30, 2014
1 parent 1cc8d7e commit ac3268a
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 6 deletions.
Expand Up @@ -33,6 +33,7 @@ public class RemoteAccessInfo implements Serializable {
private int port = 22;
private String agentName;
private boolean rememberMe;
private boolean hostAuthorized = false;

public RemoteAccessInfo(String host, String user, byte[] key) {
this.host = host;
Expand Down Expand Up @@ -120,4 +121,21 @@ public boolean getRememberMe() {
public void setRememberMe(boolean rememberMe) {
this.rememberMe = rememberMe;
}

/**
* If the host to be connected to is not known, but it is authorized, this will be true.
* Otherwise, an unknown host (that is, a host with an unknown SSH key fingerprint) will fail to be connected to.
*
* If the host is already known, but the known fingerprint is different than the real fingerprint, then
* this must be true in order to connect to it. Otherwise, the connection attempt will fail.
*
* @return flag to indicate if the host is authorized
*/
public boolean isHostAuthorized() {
return hostAuthorized;
}

public void setHostAuthorized(boolean hostAuthorized) {
this.hostAuthorized = hostAuthorized;
}
}
@@ -0,0 +1,32 @@
/*
* RHQ Management Platform
* Copyright (C) 2005-2008 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.core.domain.install.remote;

/**
* Indicates if things like the SSH handshake is missing data (e.g. a password or passphrase).
*
* @author John Mazzitelli
*/
public class SSHAccessException extends RuntimeException {
private static final long serialVersionUID = 1L;

public SSHAccessException(String message) {
super(message);
}
}
Expand Up @@ -22,6 +22,8 @@
*/
package org.rhq.coregui.server.gwt;

import javax.ejb.EJBException;

import org.rhq.core.domain.install.remote.AgentInstallInfo;
import org.rhq.core.domain.install.remote.CustomAgentInstallData;
import org.rhq.core.domain.install.remote.RemoteAccessInfo;
Expand Down Expand Up @@ -112,4 +114,18 @@ public String[] remotePathDiscover(RemoteAccessInfo remoteAccessInfo, String par
throw getExceptionToThrowToClient(t);
}
}

@Override
protected RuntimeException getExceptionToThrowToClient(Throwable t) throws RuntimeException {
// if the SSH connection failed because of a bad or missing SSH key fingerprint, a SecurityException will be thrown.
// We want that SecurityException sent back as-is to the GWT UI.
if (t instanceof SecurityException) {
return (SecurityException) t;
} else if (t instanceof EJBException) {
if (t.getCause() instanceof SecurityException) {
return (SecurityException) t.getCause();
}
}
return getExceptionToThrowToClient(t);
}
}
Expand Up @@ -23,6 +23,7 @@
package org.rhq.enterprise.server.install.remote;

import java.io.File;
import java.io.IOException;

import javax.ejb.EJB;
import javax.ejb.Stateless;
Expand All @@ -41,6 +42,7 @@
import org.rhq.enterprise.server.authz.RequiredPermission;
import org.rhq.enterprise.server.core.AgentManagerLocal;
import org.rhq.enterprise.server.system.SystemManagerLocal;
import org.rhq.enterprise.server.util.LookupUtil;

/**
* Installs, starts and stops remote agents via SSH.
Expand Down Expand Up @@ -312,7 +314,18 @@ private SSHInstallUtility getSSHConnection(RemoteAccessInfo remoteAccessInfo) {
creds = new SSHInstallUtility.Credentials(username, password);
}

SSHInstallUtility sshUtil = new SSHInstallUtility(remoteAccessInfo, creds);
SSHInstallUtility.SSHConfiguration sshConfig = new SSHInstallUtility.SSHConfiguration();

File dataDir = LookupUtil.getCoreServer().getJBossServerDataDir();
File knownHosts = new File(dataDir, "rhq_known_hosts");
try {
knownHosts.createNewFile(); // make sure it exists - this creates an empty one if there isn't one yet
} catch (IOException e) {
throw new RuntimeException("Cannot create a known_hosts file for SSH communication - aborting");
}
sshConfig.setKnownHostsFile(knownHosts.getAbsolutePath());

SSHInstallUtility sshUtil = new SSHInstallUtility(remoteAccessInfo, creds, sshConfig);
return sshUtil;
}

Expand Down
Expand Up @@ -35,6 +35,7 @@
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import com.jcraft.jsch.UserInfo;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
Expand Down Expand Up @@ -77,6 +78,76 @@ public void setPassword(String p) {
}
}

static class SSHConfiguration {
public static enum StrictHostKeyChecking {
yes, no, ask
};

private StrictHostKeyChecking strictHostKeyChecking = StrictHostKeyChecking.ask;
private String knownHostsFile = null;

public SSHConfiguration() {
}

public StrictHostKeyChecking getStrictHostKeyChecking() {
return strictHostKeyChecking;
}

public void setStrictHostKeyChecking(StrictHostKeyChecking strictHostKeyChecking) {
this.strictHostKeyChecking = strictHostKeyChecking;
}

public String getKnownHostsFile() {
return knownHostsFile;
}

public void setKnownHostsFile(String knownHostsFile) {
this.knownHostsFile = knownHostsFile;
}
}

private class SSHUserInfo implements UserInfo {

@Override
public void showMessage(String msg) {
//System.out.println(msg);
}

@Override
public boolean promptYesNo(String ques) {
// this is asking either to add the fingerprint for an unknown host or, more troubling, to replace
// a known host's fingerprint. If we were told to authorize this host, then accept both.
// If we need to do separate processing for either conditions, we can see which question it is via:
// ques.matches("(?s).*authenticity of host.*can't be established.*Are you sure you want to continue connecting.*")
// and
// ques.matches("(?s).*NASTY.*")
if (accessInfo.isHostAuthorized()) {
return true;
}
throw new SecurityException(ques);
}

@Override
public boolean promptPassword(String arg0) {
return false;
}

@Override
public boolean promptPassphrase(String arg0) {
return false;
}

@Override
public String getPassword() {
return null;
}

@Override
public String getPassphrase() {
return null;
}
};

public static final String AGENT_STATUS_NOT_INSTALLED = "Agent Not Installed";

private static final String RHQ_AGENT_LATEST_VERSION_PROP = "rhq-agent.latest.version";
Expand All @@ -89,17 +160,24 @@ public void setPassword(String p) {

private final RemoteAccessInfo accessInfo;
private final Credentials defaultCredentials;
private final SSHConfiguration sshConfiguration;

private Session session;

public SSHInstallUtility(RemoteAccessInfo accessInfo, Credentials defaultCredentials) {
public SSHInstallUtility(RemoteAccessInfo accessInfo, Credentials defaultCredentials, SSHConfiguration sshConfig) {
this.accessInfo = accessInfo;
this.defaultCredentials = defaultCredentials;

if (sshConfig == null) {
sshConfig = new SSHConfiguration();
}
this.sshConfiguration = sshConfig;

connect();
}

public SSHInstallUtility(RemoteAccessInfo accessInfo) {
this(accessInfo, null);
this(accessInfo, null, null);
}

public RemoteAccessInfo getRemoteAccessInfo() {
Expand All @@ -110,6 +188,10 @@ public void connect() {
try {
JSch jsch = new JSch();

if (sshConfiguration.getKnownHostsFile() != null) {
jsch.setKnownHosts(sshConfiguration.getKnownHostsFile());
}

//if (accessInfo.getKey() != null) {
// jsch.addIdentity(...);
//}
Expand All @@ -122,9 +204,13 @@ public void connect() {
session.setPassword(credentials.getPassword());
}

Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
if (sshConfiguration.getStrictHostKeyChecking() != null) {
Properties config = new Properties();
config.put("StrictHostKeyChecking", sshConfiguration.getStrictHostKeyChecking().name());
session.setConfig(config);
}

session.setUserInfo(new SSHUserInfo());

session.connect(CONNECTION_TIMEOUT); // making a connection with timeout.
} catch (JSchException e) {
Expand Down

0 comments on commit ac3268a

Please sign in to comment.