Supports private-keys with passphrase for config-server (#2169)
This commit is contained in:
@@ -23,11 +23,14 @@ import java.security.GeneralSecurityException;
|
||||
import java.security.KeyPair;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.apache.sshd.common.config.keys.FilePasswordProvider;
|
||||
import org.apache.sshd.common.config.keys.loader.KeyPairResourceLoader;
|
||||
import org.apache.sshd.common.session.SessionContext;
|
||||
import org.apache.sshd.common.util.io.resource.AbstractIoResource;
|
||||
import org.apache.sshd.common.util.security.SecurityUtils;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
final class KeyPairUtils {
|
||||
|
||||
private static final KeyPairResourceLoader loader = SecurityUtils.getKeyPairResourceParser();
|
||||
@@ -36,14 +39,18 @@ final class KeyPairUtils {
|
||||
|
||||
}
|
||||
|
||||
static Collection<KeyPair> load(SessionContext session, String privateKey)
|
||||
static Collection<KeyPair> load(SessionContext session, String privateKey, String passphrase)
|
||||
throws IOException, GeneralSecurityException {
|
||||
return loader.loadKeyPairs(session, new StringResource(privateKey), null);
|
||||
|
||||
FilePasswordProvider passwordProvider = StringUtils.hasText(passphrase) ? FilePasswordProvider.of(passphrase)
|
||||
: FilePasswordProvider.EMPTY;
|
||||
|
||||
return loader.loadKeyPairs(session, new StringResource(privateKey), passwordProvider);
|
||||
}
|
||||
|
||||
static boolean isValid(String privateKey) {
|
||||
static boolean isValid(String privateKey, String passphrase) {
|
||||
try {
|
||||
return !KeyPairUtils.load(null, privateKey).isEmpty();
|
||||
return !KeyPairUtils.load(null, privateKey, passphrase).isEmpty();
|
||||
}
|
||||
catch (IOException | GeneralSecurityException ignored) {
|
||||
return false;
|
||||
|
||||
@@ -83,7 +83,7 @@ public class PrivateKeyValidator implements ConstraintValidator<PrivateKeyIsVali
|
||||
|
||||
private boolean isPrivateKeyFormatCorrect(JGitEnvironmentProperties sshUriProperties,
|
||||
ConstraintValidatorContext context) {
|
||||
if (KeyPairUtils.isValid(sshUriProperties.getPrivateKey())) {
|
||||
if (KeyPairUtils.isValid(sshUriProperties.getPrivateKey(), sshUriProperties.getPassphrase())) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -212,7 +212,7 @@ public class PropertyBasedSshSessionFactory extends SshdSessionFactory {
|
||||
JGitEnvironmentProperties sshProperties = sshKeysByHostname.get(remoteAddress.getHostName());
|
||||
|
||||
return sshProperties == null ? Collections.emptyList()
|
||||
: KeyPairUtils.load(session, sshProperties.getPrivateKey());
|
||||
: KeyPairUtils.load(session, sshProperties.getPrivateKey(), sshProperties.getPassphrase());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -158,7 +158,23 @@ public class PropertyBasedSshSessionFactoryTest {
|
||||
PrivateKey privateKey = getSshPrivateKey("gitlab.example.local");
|
||||
|
||||
assertThat(privateKey).isNotNull();
|
||||
assertThat(privateKey).isEqualTo(toPrivateKey(PRIVATE_KEY));
|
||||
assertThat(privateKey).isEqualTo(toPrivateKey(PRIVATE_KEY, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void privateKeyWithPassphraseIsUsed() {
|
||||
String keyWithPassphrase = getResourceAsString("/ssh/key-with-passphrase");
|
||||
|
||||
JGitEnvironmentProperties sshKey = new JGitEnvironmentProperties();
|
||||
sshKey.setUri("git@gitlab.example.local:someorg/somerepo.git");
|
||||
sshKey.setPrivateKey(keyWithPassphrase);
|
||||
sshKey.setPassphrase("secret");
|
||||
setupSessionFactory(sshKey);
|
||||
|
||||
PrivateKey privateKey = getSshPrivateKey("gitlab.example.local");
|
||||
|
||||
assertThat(privateKey).isNotNull();
|
||||
assertThat(privateKey).isEqualTo(toPrivateKey(keyWithPassphrase, "secret"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -261,9 +277,9 @@ public class PropertyBasedSshSessionFactoryTest {
|
||||
}
|
||||
}
|
||||
|
||||
private PrivateKey toPrivateKey(String key) {
|
||||
private PrivateKey toPrivateKey(String key, String passphrase) {
|
||||
try {
|
||||
Collection<KeyPair> keyPairs = KeyPairUtils.load(null, key);
|
||||
Collection<KeyPair> keyPairs = KeyPairUtils.load(null, key, passphrase);
|
||||
|
||||
return keyPairs.isEmpty() ? null : keyPairs.iterator().next().getPrivate();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
Proc-Type: 4,ENCRYPTED
|
||||
DEK-Info: AES-128-CBC,7310DDCF47A57E8764693DFBACB0FB4A
|
||||
|
||||
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
|
||||
-----END RSA PRIVATE KEY-----
|
||||
Reference in New Issue
Block a user