Skip to content

Commit 9f847d1

Browse files
committed
Fix SSH session factory issues identified in PR review
- Fix sshConfig captured as null: build session factory lazily in configure(Transport) instead of in the constructor, so sshConfig is already set by GitManager before the factory is created - Fix StrictHostKeyChecking not working: replace non-override configure(HostConfigEntry, ClientSession) with proper override of getServerKeyDatabase() that returns an accept-all ServerKeyDatabase when StrictHostKeyChecking=no - Fix temp key file security: set POSIX 0600 permissions on the temporary private key file to prevent unauthorized reads - Fix temp key file accumulation: cache and reuse the temp key file per factory instance instead of creating a new one on every call - Remove unused delegate pattern and SshdSessionFactoryBuilder - Remove unused imports (FS, HostConfigEntry) Made-with: Cursor
1 parent 13185f0 commit 9f847d1

1 file changed

Lines changed: 37 additions & 37 deletions

File tree

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
package com.rundeck.plugin.util
22

3-
import org.apache.sshd.client.config.hosts.HostConfigEntry
43
import org.eclipse.jgit.api.TransportConfigCallback
4+
import org.eclipse.jgit.transport.CredentialsProvider
55
import org.eclipse.jgit.transport.SshTransport
66
import org.eclipse.jgit.transport.Transport
7+
import org.eclipse.jgit.transport.sshd.ServerKeyDatabase
78
import org.eclipse.jgit.transport.sshd.SshdSessionFactory
8-
import org.eclipse.jgit.transport.sshd.SshdSessionFactoryBuilder
9-
import org.eclipse.jgit.util.FS
109

1110
import java.nio.file.Files
1211
import java.nio.file.Path
12+
import java.nio.file.attribute.PosixFilePermissions
13+
import java.security.PublicKey
1314

1415
/**
1516
* SSH session factory using Apache MINA SSHD instead of JSch.
@@ -18,69 +19,68 @@ import java.nio.file.Path
1819
class PluginSshSessionFactory implements TransportConfigCallback {
1920
private byte[] privateKey
2021
Map<String, String> sshConfig
21-
private SshdSessionFactory sessionFactory
2222

2323
PluginSshSessionFactory(final byte[] privateKey) {
2424
this.privateKey = privateKey
25-
this.sessionFactory = buildSessionFactory()
26-
}
27-
28-
private SshdSessionFactory buildSessionFactory() {
29-
def builder = new SshdSessionFactoryBuilder()
30-
31-
def factory = builder
32-
.setPreferredAuthentications("publickey")
33-
.build(null)
34-
35-
return new CustomSshdSessionFactory(factory, privateKey, sshConfig)
3625
}
3726

3827
@Override
3928
void configure(final Transport transport) {
4029
if (transport in SshTransport) {
4130
SshTransport sshTransport = (SshTransport) transport
42-
sshTransport.setSshSessionFactory(sessionFactory)
31+
sshTransport.setSshSessionFactory(buildSessionFactory())
4332
}
4433
}
4534

35+
private SshdSessionFactory buildSessionFactory() {
36+
return new CustomSshdSessionFactory(privateKey, sshConfig)
37+
}
38+
4639
private static class CustomSshdSessionFactory extends SshdSessionFactory {
47-
private final SshdSessionFactory delegate
4840
private final byte[] privateKey
4941
private final Map<String, String> sshConfig
42+
private Path cachedKeyFile
5043

51-
CustomSshdSessionFactory(SshdSessionFactory delegate, byte[] privateKey, Map<String, String> sshConfig) {
44+
CustomSshdSessionFactory(byte[] privateKey, Map<String, String> sshConfig) {
5245
super(null, null)
53-
this.delegate = delegate
5446
this.privateKey = privateKey
5547
this.sshConfig = sshConfig
5648
}
5749

5850
@Override
59-
File getSshDirectory() {
60-
return delegate.getSshDirectory()
61-
}
62-
63-
@Override
64-
List<Path> getDefaultIdentities(File sshDir) {
51+
protected List<Path> getDefaultIdentities(File sshDir) {
6552
if (privateKey) {
66-
Path tempKeyFile = Files.createTempFile("rundeck-git-key-", ".pem")
67-
tempKeyFile.toFile().deleteOnExit()
68-
Files.write(tempKeyFile, privateKey)
69-
return [tempKeyFile]
53+
if (cachedKeyFile == null || !Files.exists(cachedKeyFile)) {
54+
cachedKeyFile = Files.createTempFile("rundeck-git-key-", ".pem")
55+
try {
56+
Files.setPosixFilePermissions(cachedKeyFile, PosixFilePermissions.fromString("rw-------"))
57+
} catch (UnsupportedOperationException ignored) {
58+
// Non-POSIX filesystem (e.g. Windows)
59+
}
60+
Files.write(cachedKeyFile, privateKey)
61+
cachedKeyFile.toFile().deleteOnExit()
62+
}
63+
return [cachedKeyFile]
7064
}
71-
return delegate.getDefaultIdentities(sshDir)
65+
return super.getDefaultIdentities(sshDir)
7266
}
7367

74-
void configure(HostConfigEntry hostConfig, org.apache.sshd.client.session.ClientSession session) {
75-
if (sshConfig) {
76-
if (sshConfig.containsKey('StrictHostKeyChecking')) {
77-
String value = sshConfig['StrictHostKeyChecking']
78-
if (value == 'no') {
79-
session.setServerKeyVerifier({ clientSession, remoteAddress, serverKey -> true })
68+
@Override
69+
protected ServerKeyDatabase getServerKeyDatabase(File homeDir, File sshDir) {
70+
if (sshConfig?.get('StrictHostKeyChecking') == 'no') {
71+
return new ServerKeyDatabase() {
72+
@Override
73+
List<PublicKey> lookup(String connectAddress, InetSocketAddress remoteAddress, ServerKeyDatabase.Configuration config) {
74+
return Collections.emptyList()
75+
}
76+
77+
@Override
78+
boolean accept(String connectAddress, InetSocketAddress remoteAddress, PublicKey serverKey, ServerKeyDatabase.Configuration config, CredentialsProvider provider) {
79+
return true
8080
}
8181
}
8282
}
83+
return super.getServerKeyDatabase(homeDir, sshDir)
8384
}
8485
}
8586
}
86-

0 commit comments

Comments
 (0)