Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions src/main/java/de/cronn/proxy/ssh/SshConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,24 @@ public SshProxyConfig getProxyConfiguration(String host) {
}

void addIdentity(String host) throws JSchException {
String identityFile = getIdentityFileForHost(host);
log.debug("using SSH key file {}", identityFile);
jsch.addIdentity(identityFile);
}

void addIdentity(String host, String passphrase) throws JSchException {
String identityFile = getIdentityFileForHost(host);
log.debug("using SSH key file {}", identityFile);
jsch.addIdentity(identityFile, passphrase);
}

private String getIdentityFileForHost(String host) {
Config hostConfig = getHostConfig(host);
String identityFile = hostConfig.getValue(SSH_CONFIG_KEY_IDENTITY_FILE);
if (identityFile == null) {
identityFile = getDefaultSshKeyPath().toString();
}
log.debug("using SSH key file {}", identityFile);
jsch.addIdentity(identityFile);
return identityFile;
}

public String getHostUser(String host) {
Expand Down
19 changes: 17 additions & 2 deletions src/main/java/de/cronn/proxy/ssh/SshProxy.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,22 @@ public class SshProxy implements Closeable {
private final SshConfiguration sshConfiguration;
private int timeoutMillis;

private final String passphrase;

public SshProxy() {
this(DEFAULT_TIMEOUT_MILLIS);
this(DEFAULT_TIMEOUT_MILLIS, null);
}

public SshProxy(String passphrase) {
this(DEFAULT_TIMEOUT_MILLIS, passphrase);
}

public SshProxy(int timeoutMillis) {
this(timeoutMillis, null);
}

public SshProxy(int timeoutMillis, String passphrase) {
this.passphrase = passphrase;
try {
sshConfiguration = SshConfiguration.getConfiguration();
} catch (Exception e) {
Expand All @@ -56,7 +67,11 @@ public int connect(String sshTunnelHost, String host, int port, int localPort) {
log.debug("tunneling to {}:{} via {}", host, port, sshTunnelHost);

try {
sshConfiguration.addIdentity(sshTunnelHost);
if (passphrase != null && !passphrase.isEmpty()) {
sshConfiguration.addIdentity(sshTunnelHost, passphrase);
} else {
sshConfiguration.addIdentity(sshTunnelHost);
}

SshProxyConfig proxyConfig = sshConfiguration.getProxyConfiguration(sshTunnelHost);
if (proxyConfig == null) {
Expand Down
54 changes: 54 additions & 0 deletions src/test/java/de/cronn/proxy/ssh/SshProxyTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.nio.file.StandardOpenOption;
import java.util.Arrays;

Expand Down Expand Up @@ -104,6 +105,52 @@ public void testSingleHop() throws Exception {
}
}

@Test(timeout = TEST_TIMEOUT_MILLIS)
public void testSingleHopWithPassphraseAuthentication() throws Exception {
setupNewSshKeys("id_rsa_passphrase", "id_rsa_passphrase.pub");
SshServer sshServer = setUpSshServer();
int sshServerPort = sshServer.getPort();

String hostConfigName = "localhost-" + sshServerPort;
appendToSshFile(CONFIG_FILENAME, "Host " + hostConfigName + "\n\tHostName localhost\n\tPort " + sshServerPort + "\n\n");

String testPassword = "password";

try (DummyServerSocketThread dummyServerSocketThread = new DummyServerSocketThread(TRANSFER_CHARSET, TEST_TEXT);
SshProxy sshProxy = new SshProxy(testPassword)) {
int port = sshProxy.connect(hostConfigName, "localhost", dummyServerSocketThread.getPort());

final String receivedText;
try (Socket s = new Socket(SshProxy.LOCALHOST, port);
InputStream is = s.getInputStream()) {
log.info("connected to port: {}", port);
receivedText = readLine(is);
}
assertEquals(TEST_TEXT, receivedText);
} finally {
tryStop(sshServer);
}
}

@Test(timeout = TEST_TIMEOUT_MILLIS)
public void testSingleHopWithPassphraseAuthentication_IncorrectPassphrase() throws Exception {
setupNewSshKeys("id_rsa_passphrase", "id_rsa_passphrase.pub");
SshServer sshServer = setUpSshServer();
int sshServerPort = sshServer.getPort();

String hostConfigName = "localhost-" + sshServerPort;
appendToSshFile(CONFIG_FILENAME, "Host " + hostConfigName + "\n\tHostName localhost\n\tPort " + sshServerPort + "\n\n");

String testPassword = "incorrectPassword";

assertThrows(de.cronn.proxy.ssh.SshProxyRuntimeException.class, () -> {
try (DummyServerSocketThread dummyServerSocketThread = new DummyServerSocketThread(TRANSFER_CHARSET, TEST_TEXT);
SshProxy sshProxy = new SshProxy(testPassword)) {
sshProxy.connect(hostConfigName, "localhost", dummyServerSocketThread.getPort());
}
});
}

@Test(timeout = TEST_TIMEOUT_MILLIS)
public void testSingleHop_EcDsaServer() throws Exception {
SshServer sshServer = setUpSshServer(KeyUtils.EC_ALGORITHM);
Expand Down Expand Up @@ -308,4 +355,11 @@ private void appendToSshFile(String filename, String text) throws IOException {
Files.write(config, text.getBytes(CONFIG_CHARSET), StandardOpenOption.APPEND, StandardOpenOption.CREATE);
}

private void setupNewSshKeys(String privateKeyFile, String publicKeyFile) throws IOException {
Path dotSsh = Paths.get(System.getProperty("user.home"), ".ssh");
Path TEST_RESOURCES = Paths.get("src", "test", "resources");
Files.copy(TEST_RESOURCES.resolve(privateKeyFile), dotSsh.resolve("id_rsa"), StandardCopyOption.REPLACE_EXISTING);
Files.copy(TEST_RESOURCES.resolve(publicKeyFile), dotSsh.resolve("id_rsa.pub"), StandardCopyOption.REPLACE_EXISTING);
}

}
30 changes: 30 additions & 0 deletions src/test/resources/id_rsa_passphrase
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,9601C994D8345E31A8A6A0771EFB4490

AnWhrDCv8j+dTw2jQW2BT/OKPRD6rNLLYhNzgMJGePftat3XqAx0NgDuVtQcJ4E0
e3ochpF3Pw6O7lWjZ3n06x/3ibE+L3XQJhz+tx4dTYDmB0IXC/oKpW6xVAlM1Yt3
+o9WZtpERh1+w4vWquDvumRmyjgDemuodg26FsxD/3zlxMQinBto6xivbrY+vRae
lbzZKtsbjeWWyJLsIbzLNiPtTJuaF1JzWyszFyXdhfQMx4G6pLjlZpoqFUsfVqq0
iDV0R+CnwDqdN9EpjNDR8rNj7ErBTI+CCTH/9ymMaVtMDP9PJGYWdcx+lMomBVjf
HdBam9RB78yFzaUlUjjxz3d3WUhBk/LH+JlIMarzC9yfnvanxG3PgBeK4wld0Oh/
FUOcIMffkEdipyH9KrfaUsj2xrtFp++F0F52D5tynG0i94NagAueFOQ2HF6kg3Xu
ueBXdqdHXPqGrl2pl01YwlsoM1QLSUlL+H1W/mWCMooxweOaxNbehtxU98pwcLnD
LCK33SImIY6FzL8Hst8qQWzBwL3RE2TA8McHaK5J5NzGRCVAeoF00yvy2A+Yu3FV
lf+R7bRsnkmBHwXPWkwUw9axpdb8ssRnFdJ0u19vtbxMziB/j0hM5k56WEOHnV/O
THxW457u8oiUWaXz4tUrFFE8BmmKptBUdlqe8xSBphwXIYA3GDSPFelbLuCDvDfl
lc+b9lGckjVkNTv+/PPQP6C/umF/vpH00Tbxd4U899l8k13cTw9tknYhHgpqEskx
MyjqD6K2lB9RiQbbVjhnebXXkbmiXR1izgXSibgfYEFu31BkLeyZhemR718NJ9NN
fZJwUeIsCNA4yyl4CKw+ZpDSLcVIEgcuVVFw2B6gpYDjU/yZokGDGj2YVfMOAXjV
RbevJpUQN9wU0Wnzsz05r4SRQ+vVkJYB0r3KqLqRr6Q/xWf1BQGAr5IZy+6xgWJl
vSoDSaLmHkUskajLVRJH39MNSEComRgwir+z48bHLrVBx6WhgUtQxNGLQ8jBcrer
Hd7ALtZT1nbLZOPjlGeYsiLPGKEm26+sYdm0mUwycNb2qq7MfmtqiernIiqz8EDo
aafjLsq3V95ABaE0T6wttq/xQBGYt1OLI5hcjP3NZgmEZLBI/GCrozTA1LtH0PUp
das9Ajg5LLpmMhNQqkepeJuoUiDITXyzPF/zucmksEUWUz6hyJyjf/NlSpwbtR7x
CsLwyi9VjO88PGawHjYgOSEWGNfGDXFOvzzaLw5aV49j5cUxmNCFl1s1Vs57b70o
KwKvFuGXr/gv0Br1CnDNjVuPfVyOALc6tjJMPqcbF5FiCR9qtMZH5+IL6Q4gzg/8
06UB4U3urQo2gWBxF7YTEanZyYPzIcAPitV2tinR2JpRVHRonhDMzK4UqqNUB6R7
epJRG+8dMBKhtNajigl01YFrU59+Izyfcme+1Rkbo6ragng4lXmFJZKPUEJs105A
AGlL5Hgl0VwtCIi4/HXFAsDSYc/st5SfH4AWFDAR3tyYWXYGOau7oP8+CNRJ9MAL
0o03coxyqCE3+IwHK833rX9qngFrrT/PyD2S8Ho0ZPUhSr0Tw9fhwyJ5FRPJ0t/4
-----END RSA PRIVATE KEY-----
1 change: 1 addition & 0 deletions src/test/resources/id_rsa_passphrase.pub
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCp8oAUBvW5VMHeM9F3B5xrHDOreTr2LSKBW5f178Lvt/OWcCWD01teq6L5EuND36inJIDHMOQh8+CErSi1eNkjq0zvE4cWzssRU3zUy5qnDgsEuO7Mb8l0xrew18B0rsa0gFNw2BnlQTT8CqnT+LGJiDB0U0jNdAL3f97fVQ7VOx9vdmKMz/J0PCVl6zAwnFNbmgevLRmVo6aPTnu6+uDUS2gfS/p+BRZl/2TKhbQLVZz4H/BYl6/nEflYYe9cdrnZ263/mAJ3CQplbnOGuCv/jfWJrYnO/b7yLTBwvMVUsAJM94IDKzDSnon2nn7qZhPCznKdU+CHVuJWohhhj51H krzys@krzys-21ah0082pb