Browse Source

Work around a Jsch bug: ensure the user name is set from URI

JSch unconditionally overrides the user name given in the connection
URI by the one found in ~/.ssh/config (if that does specify one for
the used host). If the SSH config file has a different user name,
we'll end up using the wrong name, which typically results in an
authentication failure or in Eclipse/EGit asking for a password for
the wrong user.

Unfortunately there is no way to prevent or circumvent this Jsch
behavior up front; it occurs already in the Session constructor at
com.jcraft.jsch.Session() and the Session.applyConfig() method. And
while there is a Session.setUserName() that would enable us to correct
this, that latter method has package visibility only.

So resort to reflection to invoke that setUserName() method to ensure
that Jsch uses the user name from the URI, if there is one.

Bug: 526778
Change-Id: Ia327099b5210a037380b2750a7fd76ff25c41a5a
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
stable-4.9
Thomas Wolf 7 years ago
parent
commit
f67af4e16b
  1. 1
      org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
  2. 1
      org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
  3. 34
      org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java

1
org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties

@ -608,6 +608,7 @@ sourceIsNotAWildcard=Source is not a wildcard.
sourceRefDoesntResolveToAnyObject=Source ref {0} doesn''t resolve to any object. sourceRefDoesntResolveToAnyObject=Source ref {0} doesn''t resolve to any object.
sourceRefNotSpecifiedForRefspec=Source ref not specified for refspec: {0} sourceRefNotSpecifiedForRefspec=Source ref not specified for refspec: {0}
squashCommitNotUpdatingHEAD=Squash commit -- not updating HEAD squashCommitNotUpdatingHEAD=Squash commit -- not updating HEAD
sshUserNameError=Jsch error: failed to set SSH user name correctly to ''{0}''; using ''{1}'' picked up from SSH config file.
sslFailureExceptionMessage=Secure connection to {0} could not be stablished because of SSL problems sslFailureExceptionMessage=Secure connection to {0} could not be stablished because of SSL problems
sslFailureInfo=A secure connection to {0}\ncould not be established because the server''s certificate could not be validated. sslFailureInfo=A secure connection to {0}\ncould not be established because the server''s certificate could not be validated.
sslFailureCause=SSL reported: {0} sslFailureCause=SSL reported: {0}

1
org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java

@ -667,6 +667,7 @@ public class JGitText extends TranslationBundle {
/***/ public String sourceRefDoesntResolveToAnyObject; /***/ public String sourceRefDoesntResolveToAnyObject;
/***/ public String sourceRefNotSpecifiedForRefspec; /***/ public String sourceRefNotSpecifiedForRefspec;
/***/ public String squashCommitNotUpdatingHEAD; /***/ public String squashCommitNotUpdatingHEAD;
/***/ public String sshUserNameError;
/***/ public String sslFailureExceptionMessage; /***/ public String sslFailureExceptionMessage;
/***/ public String sslFailureInfo; /***/ public String sslFailureInfo;
/***/ public String sslFailureCause; /***/ public String sslFailureCause;

34
org.eclipse.jgit/src/org/eclipse/jgit/transport/JschConfigSessionFactory.java

@ -53,14 +53,19 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.text.MessageFormat;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import org.eclipse.jgit.errors.TransportException; import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.internal.JGitText; import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.util.FS; import org.eclipse.jgit.util.FS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.jcraft.jsch.JSch; import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException; import com.jcraft.jsch.JSchException;
@ -80,6 +85,10 @@ import com.jcraft.jsch.UserInfo;
* to supply appropriate {@link UserInfo} to the session. * to supply appropriate {@link UserInfo} to the session.
*/ */
public abstract class JschConfigSessionFactory extends SshSessionFactory { public abstract class JschConfigSessionFactory extends SshSessionFactory {
private static final Logger LOG = LoggerFactory
.getLogger(JschConfigSessionFactory.class);
private final Map<String, JSch> byIdentityFile = new HashMap<>(); private final Map<String, JSch> byIdentityFile = new HashMap<>();
private JSch defaultJSch; private JSch defaultJSch;
@ -177,6 +186,9 @@ public abstract class JschConfigSessionFactory extends SshSessionFactory {
FS fs, String user, final String pass, String host, int port, FS fs, String user, final String pass, String host, int port,
final OpenSshConfig.Host hc) throws JSchException { final OpenSshConfig.Host hc) throws JSchException {
final Session session = createSession(hc, user, host, port, fs); final Session session = createSession(hc, user, host, port, fs);
// Jsch will have overridden the explicit user by the one from the SSH
// config file...
setUserName(session, user);
// We retry already in getSession() method. JSch must not retry // We retry already in getSession() method. JSch must not retry
// on its own. // on its own.
session.setConfig("MaxAuthTries", "1"); //$NON-NLS-1$ //$NON-NLS-2$ session.setConfig("MaxAuthTries", "1"); //$NON-NLS-1$ //$NON-NLS-2$
@ -199,6 +211,28 @@ public abstract class JschConfigSessionFactory extends SshSessionFactory {
return session; return session;
} }
private void setUserName(Session session, String userName) {
// Jsch 0.1.54 picks up the user name from the ssh config, even if an
// explicit user name was given! We must correct that if ~/.ssh/config
// has a different user name.
if (userName == null || userName.isEmpty()
|| userName.equals(session.getUserName())) {
return;
}
try {
Class<?>[] parameterTypes = { String.class };
Method method = Session.class.getDeclaredMethod("setUserName", //$NON-NLS-1$
parameterTypes);
method.setAccessible(true);
method.invoke(session, userName);
} catch (NullPointerException | IllegalAccessException
| IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
LOG.error(MessageFormat.format(JGitText.get().sshUserNameError,
userName, session.getUserName()), e);
}
}
/** /**
* Create a new remote session for the requested address. * Create a new remote session for the requested address.
* *

Loading…
Cancel
Save