Jsch overrides the port in the URI with the one in ~/.ssh/config
Jsch unconditionally overwrites the port from the ssh config file (if a port is specified there), even if the URI explicitly does give a different port. Fix this, and add tests. Change-Id: I7b014543c7ece26270e366db39d7647f82d64f0d Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
This commit is contained in:
parent
3d6455331d
commit
891103609d
|
@ -33,6 +33,10 @@ def tests(tests):
|
||||||
additional_deps = [
|
additional_deps = [
|
||||||
'//lib:jsch',
|
'//lib:jsch',
|
||||||
]
|
]
|
||||||
|
if src.endswith("JschConfigSessionFactoryTest.java"):
|
||||||
|
additional_deps = [
|
||||||
|
'//lib:jsch',
|
||||||
|
]
|
||||||
|
|
||||||
junit_tests(
|
junit_tests(
|
||||||
name = name,
|
name = name,
|
||||||
|
|
|
@ -0,0 +1,216 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch>
|
||||||
|
* and other copyright owners as documented in the project's IP log.
|
||||||
|
*
|
||||||
|
* This program and the accompanying materials are made available
|
||||||
|
* under the terms of the Eclipse Distribution License v1.0 which
|
||||||
|
* accompanies this distribution, is reproduced below, and is
|
||||||
|
* available at http://www.eclipse.org/org/documents/edl-v10.php
|
||||||
|
*
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or
|
||||||
|
* without modification, are permitted provided that the following
|
||||||
|
* conditions are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above
|
||||||
|
* copyright notice, this list of conditions and the following
|
||||||
|
* disclaimer in the documentation and/or other materials provided
|
||||||
|
* with the distribution.
|
||||||
|
*
|
||||||
|
* - Neither the name of the Eclipse Foundation, Inc. nor the
|
||||||
|
* names of its contributors may be used to endorse or promote
|
||||||
|
* products derived from this software without specific prior
|
||||||
|
* written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
|
||||||
|
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
|
||||||
|
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
package org.eclipse.jgit.transport;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.jgit.util.FS;
|
||||||
|
import org.junit.After;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.jcraft.jsch.Session;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for correctly interpreting ssh config values when Jsch sessions are
|
||||||
|
* used.
|
||||||
|
*/
|
||||||
|
public class JschConfigSessionFactoryTest {
|
||||||
|
|
||||||
|
File tmpConfigFile;
|
||||||
|
|
||||||
|
OpenSshConfig tmpConfig;
|
||||||
|
|
||||||
|
DefaultSshSessionFactory factory = new DefaultSshSessionFactory();
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void removeTmpConfig() {
|
||||||
|
if (tmpConfigFile == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (tmpConfigFile.exists() && !tmpConfigFile.delete()) {
|
||||||
|
tmpConfigFile.deleteOnExit();
|
||||||
|
}
|
||||||
|
tmpConfigFile = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNoConfigEntry() throws Exception {
|
||||||
|
tmpConfigFile = File.createTempFile("jsch", "test");
|
||||||
|
tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
|
||||||
|
tmpConfigFile);
|
||||||
|
factory.setConfig(tmpConfig);
|
||||||
|
Session session = createSession("ssh://egit/egit/egit");
|
||||||
|
assertEquals("egit", session.getHost());
|
||||||
|
// No user in URI, none in ssh config: default is OS user name
|
||||||
|
assertEquals(System.getProperty("user.name"), session.getUserName());
|
||||||
|
assertEquals(22, session.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAlias() throws Exception {
|
||||||
|
tmpConfigFile = createConfig("Host egit", "Hostname git.eclipse.org",
|
||||||
|
"User foo", "Port 29418");
|
||||||
|
tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
|
||||||
|
tmpConfigFile);
|
||||||
|
factory.setConfig(tmpConfig);
|
||||||
|
Session session = createSession("ssh://egit/egit/egit");
|
||||||
|
assertEquals("git.eclipse.org", session.getHost());
|
||||||
|
assertEquals("foo", session.getUserName());
|
||||||
|
assertEquals(29418, session.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAliasWithUser() throws Exception {
|
||||||
|
tmpConfigFile = createConfig("Host egit", "Hostname git.eclipse.org",
|
||||||
|
"User foo", "Port 29418");
|
||||||
|
tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
|
||||||
|
tmpConfigFile);
|
||||||
|
factory.setConfig(tmpConfig);
|
||||||
|
Session session = createSession("ssh://bar@egit/egit/egit");
|
||||||
|
assertEquals("git.eclipse.org", session.getHost());
|
||||||
|
assertEquals("bar", session.getUserName());
|
||||||
|
assertEquals(29418, session.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAliasWithPort() throws Exception {
|
||||||
|
tmpConfigFile = createConfig("Host egit", "Hostname git.eclipse.org",
|
||||||
|
"User foo", "Port 29418");
|
||||||
|
tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
|
||||||
|
tmpConfigFile);
|
||||||
|
factory.setConfig(tmpConfig);
|
||||||
|
Session session = createSession("ssh://bar@egit:22/egit/egit");
|
||||||
|
assertEquals("git.eclipse.org", session.getHost());
|
||||||
|
assertEquals("bar", session.getUserName());
|
||||||
|
assertEquals(22, session.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAliasIdentical() throws Exception {
|
||||||
|
tmpConfigFile = createConfig("Host git.eclipse.org",
|
||||||
|
"Hostname git.eclipse.org", "User foo", "Port 29418");
|
||||||
|
tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
|
||||||
|
tmpConfigFile);
|
||||||
|
factory.setConfig(tmpConfig);
|
||||||
|
Session session = createSession("ssh://git.eclipse.org/egit/egit");
|
||||||
|
assertEquals("git.eclipse.org", session.getHost());
|
||||||
|
assertEquals("foo", session.getUserName());
|
||||||
|
assertEquals(29418, session.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAliasIdenticalWithUser() throws Exception {
|
||||||
|
tmpConfigFile = createConfig("Host git.eclipse.org",
|
||||||
|
"Hostname git.eclipse.org", "User foo", "Port 29418");
|
||||||
|
tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
|
||||||
|
tmpConfigFile);
|
||||||
|
factory.setConfig(tmpConfig);
|
||||||
|
Session session = createSession("ssh://bar@git.eclipse.org/egit/egit");
|
||||||
|
assertEquals("git.eclipse.org", session.getHost());
|
||||||
|
assertEquals("bar", session.getUserName());
|
||||||
|
assertEquals(29418, session.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAliasIdenticalWithPort() throws Exception {
|
||||||
|
tmpConfigFile = createConfig("Host git.eclipse.org",
|
||||||
|
"Hostname git.eclipse.org", "User foo", "Port 29418");
|
||||||
|
tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
|
||||||
|
tmpConfigFile);
|
||||||
|
factory.setConfig(tmpConfig);
|
||||||
|
Session session = createSession(
|
||||||
|
"ssh://bar@git.eclipse.org:300/egit/egit");
|
||||||
|
assertEquals("git.eclipse.org", session.getHost());
|
||||||
|
assertEquals("bar", session.getUserName());
|
||||||
|
assertEquals(300, session.getPort());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testConnectTimout() throws Exception {
|
||||||
|
tmpConfigFile = createConfig("Host git.eclipse.org",
|
||||||
|
"Hostname git.eclipse.org", "User foo", "Port 29418",
|
||||||
|
"ConnectTimeout 10");
|
||||||
|
tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
|
||||||
|
tmpConfigFile);
|
||||||
|
factory.setConfig(tmpConfig);
|
||||||
|
Session session = createSession("ssh://git.eclipse.org/something");
|
||||||
|
assertEquals("git.eclipse.org", session.getHost());
|
||||||
|
assertEquals("foo", session.getUserName());
|
||||||
|
assertEquals(29418, session.getPort());
|
||||||
|
assertEquals(TimeUnit.SECONDS.toMillis(10), session.getTimeout());
|
||||||
|
}
|
||||||
|
|
||||||
|
private File createConfig(String... lines) throws Exception {
|
||||||
|
File f = File.createTempFile("jsch", "test");
|
||||||
|
Files.write(f.toPath(), Arrays.asList(lines));
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Session createSession(String uriText) throws Exception {
|
||||||
|
// For this test to make sense, these few lines must correspond to the
|
||||||
|
// code in JschConfigSessionFactory.getSession(). Because of
|
||||||
|
// side-effects we cannot encapsulate that there properly and so we have
|
||||||
|
// to duplicate this bit here. We also can't test getSession() itself
|
||||||
|
// since it would try to actually connect to a server.
|
||||||
|
URIish uri = new URIish(uriText);
|
||||||
|
String host = uri.getHost();
|
||||||
|
String user = uri.getUser();
|
||||||
|
String password = uri.getPass();
|
||||||
|
int port = uri.getPort();
|
||||||
|
OpenSshConfig.Host hostConfig = tmpConfig.lookup(host);
|
||||||
|
host = hostConfig.getHostName();
|
||||||
|
if (port <= 0) {
|
||||||
|
port = hostConfig.getPort();
|
||||||
|
}
|
||||||
|
if (user == null) {
|
||||||
|
user = hostConfig.getUser();
|
||||||
|
}
|
||||||
|
return factory.createSession(null, FS.DETECTED, user, password, host,
|
||||||
|
port, hostConfig);
|
||||||
|
}
|
||||||
|
}
|
|
@ -193,13 +193,18 @@ private static boolean isAuthenticationCanceled(JSchException e) {
|
||||||
return e.getCause() == null && e.getMessage().equals("Auth cancel"); //$NON-NLS-1$
|
return e.getCause() == null && e.getMessage().equals("Auth cancel"); //$NON-NLS-1$
|
||||||
}
|
}
|
||||||
|
|
||||||
private Session createSession(CredentialsProvider credentialsProvider,
|
// Package visibility for tests
|
||||||
|
Session createSession(CredentialsProvider credentialsProvider,
|
||||||
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
|
// Jsch will have overridden the explicit user by the one from the SSH
|
||||||
// config file...
|
// config file...
|
||||||
setUserName(session, user);
|
setUserName(session, user);
|
||||||
|
// Jsch will also have overridden the port.
|
||||||
|
if (port > 0 && port != session.getPort()) {
|
||||||
|
session.setPort(port);
|
||||||
|
}
|
||||||
// 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$
|
||||||
|
@ -477,4 +482,14 @@ public String[] getValues(String key) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the {@link OpenSshConfig} to use. Intended for use in tests.
|
||||||
|
*
|
||||||
|
* @param config
|
||||||
|
* to use
|
||||||
|
*/
|
||||||
|
void setConfig(OpenSshConfig config) {
|
||||||
|
this.config = config;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue