Skip to content

Instantly share code, notes, and snippets.

@Marthym
Created August 15, 2024 09:01
Show Gist options
  • Save Marthym/ee1000de48762535a19ead1a7511cb0b to your computer and use it in GitHub Desktop.
Save Marthym/ee1000de48762535a19ead1a7511cb0b to your computer and use it in GitHub Desktop.
java-database-connection-through-ssh
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<properties>
<sshd-core.version>2.13.1</sshd-core.version>
<eddsa.version>0.3.0</eddsa.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.sshd</groupId>
<artifactId>sshd-core</artifactId>
<version>${sshd-core.version}</version>
</dependency>
<dependency>
<groupId>net.i2p.crypto</groupId>
<artifactId>eddsa</artifactId>
<version>${eddsa.version}</version>
<scope>runtime</scope>
</dependency>
</dependencies>
</project>
import com.machinezoo.noexception.Exceptions;
import lombok.extern.slf4j.Slf4j;
import org.apache.sshd.client.SshClient;
import org.apache.sshd.client.config.hosts.HostConfigEntry;
import org.apache.sshd.client.session.ClientSession;
import org.apache.sshd.common.config.keys.FilePasswordProvider;
import org.apache.sshd.common.util.net.SshdSocketAddress;
import java.io.IOException;
import java.net.InetAddress;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import static java.util.Objects.nonNull;
public class SshPortsForwards implements AutoCloseable {
private static final Duration SSH_TIMEOUT = Duration.ofSeconds(10);
private static final int DEFAULT_PORT_FORWARD_STRING_COMPONENTS = 3;
private final SshClient sshClient;
private final List<ClientSession> sessions;
public SshPortsForwards(SshProperties sshProperties) {
if (nonNull(sshProperties)) {
this.sshClient = SshClient.setUpDefaultClient();
this.sessions = new ArrayList<>(sshProperties.connexions().size());
configure(sshProperties);
} else {
this.sshClient = null;
this.sessions = List.of();
}
}
private void configure(SshProperties sshProperties) {
try {
if (nonNull(sshProperties.keysPassword())) {
sshClient.setFilePasswordProvider(FilePasswordProvider.of(sshProperties.keysPassword()));
}
sshClient.start();
for (SshConnexionProperties connexionProperties : sshProperties.connexions()) {
if (nonNull(connexionProperties.url())) {
createSshConnexion(connexionProperties);
}
}
} catch (SshException e) {
close();
throw e;
}
}
private void createSshConnexion(SshConnexionProperties connexionProperties) {
HostConfigEntry sshHostEntry = new HostConfigEntry();
try {
sshHostEntry.setHost(connexionProperties.url().getHost());
sshHostEntry.setHostName(InetAddress.getByName(connexionProperties.url().getHost()).getHostAddress());
sshHostEntry.setPort(connexionProperties.url().getPort());
sshHostEntry.appendPropertyValue("ForwardAgent", "yes");
if (nonNull(connexionProperties.url().getUserInfo())) {
sshHostEntry.setUsername(connexionProperties.url().getUserInfo());
}
if (nonNull(connexionProperties.proxyJump())) {
String jump = connexionProperties.proxyJump().getUserInfo()
+ "@" + InetAddress.getByName(connexionProperties.proxyJump().getHost()).getHostAddress()
+ ":" + connexionProperties.proxyJump().getPort();
log.atDebug().addArgument(jump).log("Configure proxyJump to {}");
sshHostEntry.setProxyJump(jump);
}
ClientSession session = sshClient.connect(sshHostEntry)
.verify(SSH_TIMEOUT.toMillis())
.getSession();
log.atDebug().addArgument(sshHostEntry).log("Connection to {} established ...");
session.auth().verify(SSH_TIMEOUT);
log.atDebug().addArgument(sshHostEntry).log("Authentication to {} accepted ...");
sessions.add(session);
for (String portForwardString : connexionProperties.portsForwards()) {
if (nonNull(portForwardString) && !portForwardString.isBlank()) {
String[] portForward = portForwardString.split(":");
if (portForward.length == DEFAULT_PORT_FORWARD_STRING_COMPONENTS) {
SshdSocketAddress remote = new SshdSocketAddress(portForward[1], Integer.parseInt(portForward[2]));
session.startLocalPortForwarding(Integer.parseInt(portForward[0]), remote);
log.atDebug()
.addArgument(portForward)
.log("Port forwarding {} created");
}
}
}
} catch (IOException e) {
close();
throw new SshException("Unable to create ssh connection " + sshHostEntry, e);
}
}
@Override
public void close() {
sessions.forEach(Exceptions.wrap().consumer(ClientSession::close));
if (nonNull(sshClient)) {
sshClient.stop();
log.atInfo().log("SSH Connection closed gracefully !");
}
}
}
public record SshProperties(
String keysPassword,
List<SshConnexionProperties> connexions
) {
}
public record SshConnexionProperties(
String name,
URI url,
URI proxyJump,
List<String> portsForwards
) {
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment