in git-common/src/main/java/jetbrains/buildServer/buildTriggers/vcs/git/command/GitCommandLine.java [195:300]
private void configureGitSshCommand(@NotNull GitCommandSettings settings) throws VcsException {
final AuthSettings authSettings = settings.getAuthSettings();
if (authSettings == null) return;
//Git has 2 environment variables related to ssh: GIT_SSH and GIT_SSH_COMMAND.
//We use GIT_SSH_COMMAND because git resolves the executable specified in it,
//i.e. it finds the 'ssh' executable which is not in the PATH on windows by default.
//We specify the following command:
//
// GIT_SSH_COMMAND=ssh -i "<path to decrypted key>" (-o "StrictHostKeyChecking=no" -vvv)
//
//The key is decrypted by us because on MacOS ssh seems to ignore the SSH_ASKPASS and
//runs the MacOS graphical keychain helper. Disabling it via the -o "KeychainIntegration=no"
//option results in the 'Bad configuration option: keychainintegration' error.
final boolean ignoreKnownHosts = isIgnoreKnownHosts(authSettings);
final String sendEnv = getSshRequestToken();
File privateKey = null;
try {
privateKey = getPrivateKey(authSettings);
if (privateKey != null || ignoreKnownHosts || StringUtil.isNotEmpty(sendEnv)) {
final StringBuilder gitSshCommand = new StringBuilder("ssh");
if (privateKey != null) {
gitSshCommand.append(" -i \"").append(privateKey.getAbsolutePath().replace('\\', '/')).append("\"");
if (!TeamCityProperties.getBoolean(SSH_FALLBACK_TO_DEFAULT_CONFIG)) {
gitSshCommand.append(" -F \"none\"");
}
}
if (ignoreKnownHosts) {
gitSshCommand.append(" -o \"StrictHostKeyChecking=no\" -o \"UserKnownHostsFile=/dev/null\" -o \"GlobalKnownHostsFile=/dev/null\"");
} else {
String knownHosts = myCtx.getSshKnownHosts(authSettings);
if (knownHosts == null) {
myLogger.warning(
"\"Ignore known hosts database\" setting is disabled, please make sure that per-user or global known host key database contains remote host key, otherwise git operations may hang or fail in unexpected way");
} else {
File knownHostsFile = FileUtil.createTempFile(myCtx.getTempDir(), "known_hosts", "", true);
addPostAction(() -> FileUtil.delete(knownHostsFile));
try (FileWriter writer = new FileWriter(knownHostsFile)) {
writer.write(knownHosts);
}
String knownHostsPath = knownHostsFile.getAbsolutePath();
gitSshCommand.append(String.format(" -o \"UserKnownHostsFile=%s\" -o \"GlobalKnownHostsFile=%s\"", knownHostsPath, knownHostsPath));
}
}
if (myProxy.isSshProxyEnabled()) {
int port = myProxy.getSshProxyPort();
String fullProxyAddr = port != 0 ? String.format("%s:%d", myProxy.getSshProxyHost(), port) : myProxy.getSshProxyHost();
String socksProxyCommand;
if (myProxy.getCustomSshProxyCommand() != null) {
String customCommand = myProxy.getCustomSshProxyCommand();
customCommand = customCommand.replace("%host", myProxy.getSshProxyHost()); // not null because isSshProxyEnabled check
customCommand = customCommand.replace("%port", String.valueOf(myProxy.getSshProxyPort()));
socksProxyCommand = String.format(" -o ProxyCommand=\"%s %%h %%p\"", customCommand);
} else if (SystemInfo.isWindows) {
String strType;
if (myProxy.getSshProxyType() == ProxyHandler.SshProxyType.HTTP) {
// http proxy
strType = "H";
} else {
// socks proxy
strType = "S";
}
socksProxyCommand = String.format(" -o ProxyCommand=\"connect -%s %s %%h %%p\"", strType, fullProxyAddr);
} else {
String strType;
switch (Objects.requireNonNull(myProxy.getSshProxyType())) {
case SOCKS4: strType = "4"; break;
case SOCKS5: strType = "5"; break;
default: strType = "connect"; break;
}
socksProxyCommand = String.format(" -o ProxyCommand=\"nc -v -X %s -x %s %%h %%p\"", strType, fullProxyAddr);
}
gitSshCommand.append(socksProxyCommand);
}
if (authSettings.getAuthMethod().isKeyAuth()) {
gitSshCommand.append(" -o \"PreferredAuthentications=publickey\" -o \"PasswordAuthentication=no\" -o \"KbdInteractiveAuthentication=no\"");
} else {
gitSshCommand.append(" -o \"PreferredAuthentications=password,keyboard-interactive\" -o \"PubkeyAuthentication=no\"");
}
gitSshCommand.append(" -o \"IdentitiesOnly=yes\"");
if (StringUtil.isNotEmpty(sendEnv)) {
gitSshCommand.append(" -o \"SetEnv TEAMCITY_SSH_REQUEST_TOKEN").append("=").append(sendEnv).append("\"");
}
final String sshCommandOptions = myCtx.getSshCommandOptions();
if (StringUtil.isNotEmpty(sshCommandOptions)) {
gitSshCommand.append(" ").append(sshCommandOptions);
}
if (myCtx.isDebugSsh() || settings.isTrace()) {
gitSshCommand.append(" -vvv");
}
addEnvParam("GIT_SSH_COMMAND", gitSshCommand.toString());
}
} catch (Exception e) {
if (privateKey != null)
FileUtil.delete(privateKey);
if (e instanceof VcsException)
throw (VcsException) e;
throw new VcsException(e);
}
}