TW-53210 disable gssapi-with-mic ssh authentication
authorDmitry Neverov <dmitry.neverov@gmail.com>
Wed, 10 Jan 2018 12:00:38 +0000 (13:00 +0100)
committerDmitry Neverov <dmitry.neverov@gmail.com>
Wed, 10 Jan 2018 12:00:38 +0000 (13:00 +0100)
It wasn't supported in the trilead-based ssh client (used before
2017.2.1), so disabling it should not break anything. Problem with
gssapi-with-mic is that by default java asks a user for credentials and
waits for input from stdin, as a result checkout fails by timeout.

Also now we specify a custom security callback handler instead of the
default one which uses stdin. Our handler doesn't provide any
credentials, but will work if the agent machine already has the required
kerberos ticket.

git-agent/src/jetbrains/buildServer/buildTriggers/vcs/git/agent/BuildContext.java
git-agent/src/jetbrains/buildServer/buildTriggers/vcs/git/agent/Context.java
git-agent/src/jetbrains/buildServer/buildTriggers/vcs/git/agent/GitCommandLine.java
git-agent/src/jetbrains/buildServer/buildTriggers/vcs/git/agent/JSchClient.java
git-agent/src/jetbrains/buildServer/buildTriggers/vcs/git/agent/NoBuildContext.java
git-agent/src/jetbrains/buildServer/buildTriggers/vcs/git/agent/command/impl/SshHandler.java
git-agent/src/org/jetbrains/git4idea/ssh/GitSSHHandler.java

index 704c936f32a1a706fa2309da5261ac66f87b5a0d..cf5fb6d0cf5a95ad295273e14b18c1ce198a210c 100644 (file)
@@ -47,6 +47,15 @@ public class BuildContext implements Context {
     return null;
   }
 
+  @Nullable
+  @Override
+  public String getPreferredSshAuthMethods() {
+    String value = myBuild.getSharedConfigParameters().get("teamcity.git.sshPreferredAuthMethods");
+    if (!StringUtil.isEmpty(value))
+      return value;
+    return "publickey,keyboard-interactive,password";
+  }
+
   @Override
   public boolean isProvideCredHelper() {
     return myConfig.isProvideCredHelper();
index c214f8fb9374e95cc5a2945c5082d7e04888ca10..a784d548b3263ca17be64cb063210b291018e72f 100644 (file)
@@ -27,6 +27,9 @@ public interface Context {
   @Nullable
   String getSshMacType();
 
+  @Nullable
+  String getPreferredSshAuthMethods();
+
   boolean isProvideCredHelper();
 
 }
index ecd8886f081932d9ff5e9e041c4d8ac3d8c94ffc..04736d043bdc84b54009fb32fa3819f96b780e52 100644 (file)
@@ -119,7 +119,7 @@ public class GitCommandLine extends GeneralCommandLine {
       if (settings.isUseNativeSsh()) {
         return CommandUtil.runCommand(this, settings.getTimeout());
       } else {
-        SshHandler h = new SshHandler(mySsh, mySshKeyManager, authSettings, this, myTmpDir, myCtx.getSshMacType());
+        SshHandler h = new SshHandler(mySsh, mySshKeyManager, authSettings, this, myTmpDir, myCtx);
         try {
           return CommandUtil.runCommand(this, settings.getTimeout());
         } finally {
index a6867e8ff9417289d93feab38818f6bb4bc8e2fd..11235dbe73640102386d486647503c5b0cbac83b 100644 (file)
 
 package jetbrains.buildServer.buildTriggers.vcs.git.agent;
 
-import com.jcraft.jsch.*;
+import com.jcraft.jsch.ChannelExec;
+import com.jcraft.jsch.JSch;
+import com.jcraft.jsch.Logger;
+import com.jcraft.jsch.Session;
 import jetbrains.buildServer.buildTriggers.vcs.git.GitUtils;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.jetbrains.git4idea.ssh.GitSSHHandler;
 
+import javax.security.auth.callback.Callback;
+import javax.security.auth.callback.CallbackHandler;
+import javax.security.auth.callback.UnsupportedCallbackException;
 import java.io.File;
 import java.io.InputStream;
+import java.security.Security;
 import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -148,6 +155,12 @@ public class JSchClient {
         }
       }
 
+      String authMethods = System.getenv(GitSSHHandler.TEAMCITY_SSH_PREFERRED_AUTH_METHODS);
+      if (authMethods != null && authMethods.length() > 0)
+        session.setConfig("PreferredAuthentications", authMethods);
+
+      EmptySecurityCallbackHandler.install();
+
       session.connect();
 
       channel = (ChannelExec) session.openChannel("exec");
@@ -262,4 +275,20 @@ public class JSchClient {
         return "UNKNOWN";
     }
   }
+
+
+  // Doesn't provide any credentials, used instead the default handler from jdk
+  // which reads credentials them from stdin.
+  public static class EmptySecurityCallbackHandler implements CallbackHandler {
+    @Override
+    public void handle(final Callback[] callbacks) throws UnsupportedCallbackException {
+      if (callbacks.length > 0) {
+        throw new UnsupportedCallbackException(callbacks[0], "Unsupported callback");
+      }
+    }
+
+    static void install() {
+      Security.setProperty("auth.login.defaultCallbackHandler", EmptySecurityCallbackHandler.class.getName());
+    }
+  }
 }
index 437250a22dd350535b3af657b5db005bc6040f55..359a5c331f2c3a0e5bfff7a6a33cc72b3ed8a791 100644 (file)
@@ -33,6 +33,12 @@ public class NoBuildContext implements Context {
     return null;
   }
 
+  @Nullable
+  @Override
+  public String getPreferredSshAuthMethods() {
+    return null;
+  }
+
   @Override
   public boolean isProvideCredHelper() {
     return false;
index f5c101cf9ed2ab16a2d51aa8fc14bb57fcfa907f..41c73491150bdbc4f6b97f663a02480921b3c9d2 100644 (file)
@@ -18,6 +18,7 @@ package jetbrains.buildServer.buildTriggers.vcs.git.agent.command.impl;
 
 import jetbrains.buildServer.buildTriggers.vcs.git.AuthSettings;
 import jetbrains.buildServer.buildTriggers.vcs.git.AuthenticationMethod;
+import jetbrains.buildServer.buildTriggers.vcs.git.agent.Context;
 import jetbrains.buildServer.buildTriggers.vcs.git.agent.GitCommandLine;
 import jetbrains.buildServer.log.Loggers;
 import jetbrains.buildServer.ssh.TeamCitySshKey;
@@ -64,7 +65,7 @@ public class SshHandler implements GitSSHService.Handler {
                     @NotNull AuthSettings authSettings,
                     @NotNull GitCommandLine cmd,
                     @NotNull File tmpDir,
-                    @Nullable String customSshMacType) throws VcsException {
+                    @NotNull Context ctx) throws VcsException {
     mySsh = ssh;
     myAuthSettings = authSettings;
     cmd.addEnvParam(GitSSHHandler.SSH_PORT_ENV, Integer.toString(mySsh.getXmlRcpPort()));
@@ -91,8 +92,10 @@ public class SshHandler implements GitSSHService.Handler {
         }
       }
     }
-    if (customSshMacType != null)
-      cmd.addEnvParam(GitSSHHandler.TEAMCITY_SSH_MAC_TYPE, customSshMacType);
+    if (ctx.getSshMacType() != null)
+      cmd.addEnvParam(GitSSHHandler.TEAMCITY_SSH_MAC_TYPE, ctx.getSshMacType());
+    if (ctx.getPreferredSshAuthMethods() != null)
+      cmd.addEnvParam(GitSSHHandler.TEAMCITY_SSH_PREFERRED_AUTH_METHODS, ctx.getPreferredSshAuthMethods());
     cmd.addEnvParam(GitSSHHandler.TEAMCITY_DEBUG_SSH, String.valueOf(Loggers.VCS.isDebugEnabled()));
     try {
       cmd.addEnvParam(GitSSHHandler.GIT_SSH_ENV, ssh.getScriptPath());
index 551de76041bce32d6a407d9b0b05dbf4342c9e6c..8e427e5305ab04defafeca321fd337de87d2b5f8 100644 (file)
@@ -54,6 +54,7 @@ public interface GitSSHHandler {
   String TEAMCITY_PASSPHRASE = "TEAMCITY_PASSPHRASE";
   String TEAMCITY_DEBUG_SSH = "TEAMCITY_DEBUG_SSH";
   String TEAMCITY_SSH_MAC_TYPE = "TEAMCITY_SSH_MAC_TYPE";
+  String TEAMCITY_SSH_PREFERRED_AUTH_METHODS = "TEAMCITY_SSH_MAC_TYPE";
   String TEAMCITY_VERSION = "TEAMCITY_VERSION";
 
   /**