From 9683bc71b6c05ce1ca2b5d6c6f7d74fff3db8429 Mon Sep 17 00:00:00 2001 From: Matthias Sohn Date: Sun, 12 Sep 2021 23:35:33 +0200 Subject: Fix split package in bundle org.eclipse.jgit.ssh.jsch The package org.eclipse.jgit.transport was split between org.eclipse.jgit and org.eclipse.jgit.ssh.jsch. Bug: 564544 Change-Id: I91d38e67c65ed97a880f8dc8f9559663b9eec33b --- .../jgit/transport/JSchSshProtocol2Test.java | 92 ---- .../org/eclipse/jgit/transport/JSchSshTest.java | 86 --- .../transport/JschConfigSessionFactoryTest.java | 262 --------- .../eclipse/jgit/transport/OpenSshConfigTest.java | 592 --------------------- .../transport/ssh/jsch/JSchSshProtocol2Test.java | 96 ++++ .../jgit/transport/ssh/jsch/JSchSshTest.java | 89 ++++ .../ssh/jsch/JschConfigSessionFactoryTest.java | 263 +++++++++ .../jgit/transport/ssh/jsch/OpenSshConfigTest.java | 592 +++++++++++++++++++++ 8 files changed, 1040 insertions(+), 1032 deletions(-) delete mode 100644 org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/JSchSshProtocol2Test.java delete mode 100644 org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/JSchSshTest.java delete mode 100644 org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/JschConfigSessionFactoryTest.java delete mode 100644 org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java create mode 100644 org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JSchSshProtocol2Test.java create mode 100644 org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JSchSshTest.java create mode 100644 org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JschConfigSessionFactoryTest.java create mode 100644 org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/OpenSshConfigTest.java (limited to 'org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport') diff --git a/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/JSchSshProtocol2Test.java b/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/JSchSshProtocol2Test.java deleted file mode 100644 index 0929c55c07..0000000000 --- a/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/JSchSshProtocol2Test.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright (C) 2020 Thomas Wolf and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -//TODO(ms): move to org.eclipse.jgit.ssh.jsch in 6.0 -package org.eclipse.jgit.transport; - -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.util.Arrays; - -import org.eclipse.jgit.errors.TransportException; -import org.eclipse.jgit.junit.ssh.SshBasicTestBase; -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.lib.Repository; -import org.eclipse.jgit.lib.StoredConfig; -import org.eclipse.jgit.transport.OpenSshConfig.Host; -import org.eclipse.jgit.util.FS; - -import com.jcraft.jsch.JSch; -import com.jcraft.jsch.JSchException; -import com.jcraft.jsch.Session; - -public class JSchSshProtocol2Test extends SshBasicTestBase { - - private class TestSshSessionFactory extends JschConfigSessionFactory { - - @Override - protected void configure(Host hc, Session session) { - // Nothing - } - - @Override - public synchronized RemoteSession getSession(URIish uri, - CredentialsProvider credentialsProvider, FS fs, int tms) - throws TransportException { - return super.getSession(uri, credentialsProvider, fs, tms); - } - - @Override - protected JSch createDefaultJSch(FS fs) throws JSchException { - JSch defaultJSch = super.createDefaultJSch(fs); - if (knownHosts.exists()) { - defaultJSch.setKnownHosts(knownHosts.getAbsolutePath()); - } - return defaultJSch; - } - } - - @Override - protected SshSessionFactory createSessionFactory() { - return new TestSshSessionFactory(); - } - - @Override - protected void installConfig(String... config) { - SshSessionFactory factory = getSessionFactory(); - assertTrue(factory instanceof JschConfigSessionFactory); - JschConfigSessionFactory j = (JschConfigSessionFactory) factory; - try { - j.setConfig(createConfig(config)); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private OpenSshConfig createConfig(String... content) throws IOException { - File configFile = new File(sshDir, Constants.CONFIG); - if (content != null) { - Files.write(configFile.toPath(), Arrays.asList(content)); - } - return new OpenSshConfig(getTemporaryDirectory(), configFile); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - StoredConfig config = ((Repository) db).getConfig(); - config.setInt("protocol", null, "version", 2); - config.save(); - } -} diff --git a/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/JSchSshTest.java b/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/JSchSshTest.java deleted file mode 100644 index 22caebdac2..0000000000 --- a/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/JSchSshTest.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2018, Thomas Wolf and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -//TODO(ms): move to org.eclipse.jgit.ssh.jsch in 6.0 -package org.eclipse.jgit.transport; - -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.IOException; -import java.io.UncheckedIOException; -import java.nio.file.Files; -import java.util.Arrays; - -import org.eclipse.jgit.errors.TransportException; -import org.eclipse.jgit.junit.ssh.SshTestBase; -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.transport.OpenSshConfig.Host; -import org.eclipse.jgit.util.FS; -import org.junit.experimental.theories.Theories; -import org.junit.runner.RunWith; - -import com.jcraft.jsch.JSch; -import com.jcraft.jsch.JSchException; -import com.jcraft.jsch.Session; - -@RunWith(Theories.class) -public class JSchSshTest extends SshTestBase { - - private class TestSshSessionFactory extends JschConfigSessionFactory { - - @Override - protected void configure(Host hc, Session session) { - // Nothing - } - - @Override - public synchronized RemoteSession getSession(URIish uri, - CredentialsProvider credentialsProvider, FS fs, int tms) - throws TransportException { - return super.getSession(uri, credentialsProvider, fs, tms); - } - - @Override - protected JSch createDefaultJSch(FS fs) throws JSchException { - JSch defaultJSch = super.createDefaultJSch(fs); - if (knownHosts.exists()) { - defaultJSch.setKnownHosts(knownHosts.getAbsolutePath()); - } - return defaultJSch; - } - } - - @Override - protected SshSessionFactory createSessionFactory() { - return new TestSshSessionFactory(); - } - - @Override - protected void installConfig(String... config) { - SshSessionFactory factory = getSessionFactory(); - assertTrue(factory instanceof JschConfigSessionFactory); - JschConfigSessionFactory j = (JschConfigSessionFactory) factory; - try { - j.setConfig(createConfig(config)); - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - private OpenSshConfig createConfig(String... content) throws IOException { - File configFile = new File(sshDir, Constants.CONFIG); - if (content != null) { - Files.write(configFile.toPath(), Arrays.asList(content)); - } - return new OpenSshConfig(getTemporaryDirectory(), configFile); - } - -} diff --git a/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/JschConfigSessionFactoryTest.java b/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/JschConfigSessionFactoryTest.java deleted file mode 100644 index 4efeae1906..0000000000 --- a/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/JschConfigSessionFactoryTest.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (C) 2018, Thomas Wolf and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -//TODO(ms): move to org.eclipse.jgit.ssh.jsch in 6.0 -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.junit.MockSystemReader; -import org.eclipse.jgit.util.FS; -import org.eclipse.jgit.util.SystemReader; -import org.junit.After; -import org.junit.Before; -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; - - JschConfigSessionFactory factory = new JschConfigSessionFactory(); - - @Before - public void setup() { - SystemReader.setInstance(new MockSystemReader()); - } - - @After - public void removeTmpConfig() { - SystemReader.setInstance(null); - 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(SystemReader.getInstance().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()); - } - - @Test - public void testAliasCaseDifferenceUpcase() throws Exception { - tmpConfigFile = createConfig("Host Bitbucket.org", - "Hostname bitbucket.org", "User foo", "Port 29418", - "ConnectTimeout 10", // - "Host bitbucket.org", "Hostname bitbucket.org", "User bar", - "Port 22", "ConnectTimeout 5"); - tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(), - tmpConfigFile); - factory.setConfig(tmpConfig); - Session session = createSession("ssh://Bitbucket.org/something"); - assertEquals("bitbucket.org", session.getHost()); - assertEquals("foo", session.getUserName()); - assertEquals(29418, session.getPort()); - assertEquals(TimeUnit.SECONDS.toMillis(10), session.getTimeout()); - } - - @Test - public void testAliasCaseDifferenceLowcase() throws Exception { - tmpConfigFile = createConfig("Host Bitbucket.org", - "Hostname bitbucket.org", "User foo", "Port 29418", - "ConnectTimeout 10", // - "Host bitbucket.org", "Hostname bitbucket.org", "User bar", - "Port 22", "ConnectTimeout 5"); - tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(), - tmpConfigFile); - factory.setConfig(tmpConfig); - Session session = createSession("ssh://bitbucket.org/something"); - assertEquals("bitbucket.org", session.getHost()); - assertEquals("bar", session.getUserName()); - assertEquals(22, session.getPort()); - assertEquals(TimeUnit.SECONDS.toMillis(5), session.getTimeout()); - } - - @Test - public void testAliasCaseDifferenceUpcaseInverted() throws Exception { - tmpConfigFile = createConfig("Host bitbucket.org", - "Hostname bitbucket.org", "User bar", "Port 22", - "ConnectTimeout 5", // - "Host Bitbucket.org", "Hostname bitbucket.org", "User foo", - "Port 29418", "ConnectTimeout 10"); - tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(), - tmpConfigFile); - factory.setConfig(tmpConfig); - Session session = createSession("ssh://Bitbucket.org/something"); - assertEquals("bitbucket.org", session.getHost()); - assertEquals("foo", session.getUserName()); - assertEquals(29418, session.getPort()); - assertEquals(TimeUnit.SECONDS.toMillis(10), session.getTimeout()); - } - - @Test - public void testAliasCaseDifferenceLowcaseInverted() throws Exception { - tmpConfigFile = createConfig("Host bitbucket.org", - "Hostname bitbucket.org", "User bar", "Port 22", - "ConnectTimeout 5", // - "Host Bitbucket.org", "Hostname bitbucket.org", "User foo", - "Port 29418", "ConnectTimeout 10"); - tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(), - tmpConfigFile); - factory.setConfig(tmpConfig); - Session session = createSession("ssh://bitbucket.org/something"); - assertEquals("bitbucket.org", session.getHost()); - assertEquals("bar", session.getUserName()); - assertEquals(22, session.getPort()); - assertEquals(TimeUnit.SECONDS.toMillis(5), 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); - if (port <= 0) { - port = hostConfig.getPort(); - } - if (user == null) { - user = hostConfig.getUser(); - } - return factory.createSession(null, FS.DETECTED, user, password, host, - port, hostConfig); - } -} diff --git a/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java b/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java deleted file mode 100644 index 93d85e2e90..0000000000 --- a/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java +++ /dev/null @@ -1,592 +0,0 @@ -/* - * Copyright (C) 2008, 2021 Google Inc. and others - * - * This program and the accompanying materials are made available under the - * terms of the Eclipse Distribution License v. 1.0 which is available at - * https://www.eclipse.org/org/documents/edl-v10.php. - * - * SPDX-License-Identifier: BSD-3-Clause - */ - -//TODO(ms): move to org.eclipse.jgit.ssh.jsch in 6.0 -package org.eclipse.jgit.transport; - -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNotSame; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.time.Instant; -import java.util.concurrent.TimeUnit; - -import org.eclipse.jgit.junit.RepositoryTestCase; -import org.eclipse.jgit.lib.Constants; -import org.eclipse.jgit.transport.OpenSshConfig.Host; -import org.eclipse.jgit.util.FS; -import org.eclipse.jgit.util.FileUtils; -import org.eclipse.jgit.util.SystemReader; -import org.junit.Before; -import org.junit.Test; - -import com.jcraft.jsch.ConfigRepository; -import com.jcraft.jsch.ConfigRepository.Config; - -public class OpenSshConfigTest extends RepositoryTestCase { - private File home; - - private File configFile; - - private OpenSshConfig osc; - - @Override - @Before - public void setUp() throws Exception { - super.setUp(); - - home = new File(trash, "home"); - FileUtils.mkdir(home); - - configFile = new File(new File(home, ".ssh"), Constants.CONFIG); - FileUtils.mkdir(configFile.getParentFile()); - - mockSystemReader.setProperty(Constants.OS_USER_NAME_KEY, "jex_junit"); - mockSystemReader.setProperty("TST_VAR", "TEST"); - osc = new OpenSshConfig(home, configFile); - } - - private void config(String data) throws IOException { - FS fs = FS.DETECTED; - long resolution = FS.getFileStoreAttributes(configFile.toPath()) - .getFsTimestampResolution().toNanos(); - Instant lastMtime = fs.lastModifiedInstant(configFile); - do { - try (final OutputStreamWriter fw = new OutputStreamWriter( - new FileOutputStream(configFile), UTF_8)) { - fw.write(data); - TimeUnit.NANOSECONDS.sleep(resolution); - } catch (InterruptedException e) { - Thread.interrupted(); - } - } while (lastMtime.equals(fs.lastModifiedInstant(configFile))); - } - - @Test - public void testNoConfig() { - final Host h = osc.lookup("repo.or.cz"); - assertNotNull(h); - assertEquals("repo.or.cz", h.getHostName()); - assertEquals("jex_junit", h.getUser()); - assertEquals(22, h.getPort()); - assertEquals(1, h.getConnectionAttempts()); - assertNull(h.getIdentityFile()); - } - - @Test - public void testSeparatorParsing() throws Exception { - config("Host\tfirst\n" + - "\tHostName\tfirst.tld\n" + - "\n" + - "Host second\n" + - " HostName\tsecond.tld\n" + - "Host=third\n" + - "HostName=third.tld\n\n\n" + - "\t Host = fourth\n\n\n" + - " \t HostName\t=fourth.tld\n" + - "Host\t = last\n" + - "HostName \t last.tld"); - assertNotNull(osc.lookup("first")); - assertEquals("first.tld", osc.lookup("first").getHostName()); - assertNotNull(osc.lookup("second")); - assertEquals("second.tld", osc.lookup("second").getHostName()); - assertNotNull(osc.lookup("third")); - assertEquals("third.tld", osc.lookup("third").getHostName()); - assertNotNull(osc.lookup("fourth")); - assertEquals("fourth.tld", osc.lookup("fourth").getHostName()); - assertNotNull(osc.lookup("last")); - assertEquals("last.tld", osc.lookup("last").getHostName()); - } - - @Test - public void testQuoteParsing() throws Exception { - config("Host \"good\"\n" + - " HostName=\"good.tld\"\n" + - " Port=\"6007\"\n" + - " User=\"gooduser\"\n" + - "Host multiple unquoted and \"quoted\" \"hosts\"\n" + - " Port=\"2222\"\n" + - "Host \"spaced\"\n" + - "# Bad host name, but testing preservation of spaces\n" + - " HostName=\" spaced\ttld \"\n" + - "# Misbalanced quotes\n" + - "Host \"bad\"\n" + - "# OpenSSH doesn't allow this but ...\n" + - " HostName=bad.tld\"\n"); - assertEquals("good.tld", osc.lookup("good").getHostName()); - assertEquals("gooduser", osc.lookup("good").getUser()); - assertEquals(6007, osc.lookup("good").getPort()); - assertEquals(2222, osc.lookup("multiple").getPort()); - assertEquals(2222, osc.lookup("quoted").getPort()); - assertEquals(2222, osc.lookup("and").getPort()); - assertEquals(2222, osc.lookup("unquoted").getPort()); - assertEquals(2222, osc.lookup("hosts").getPort()); - assertEquals(" spaced\ttld ", osc.lookup("spaced").getHostName()); - assertEquals("bad.tld\"", osc.lookup("bad").getHostName()); - } - - @Test - public void testCaseInsensitiveKeyLookup() throws Exception { - config("Host orcz\n" + "Port 29418\n" - + "\tHostName repo.or.cz\nStrictHostKeyChecking yes\n"); - final Host h = osc.lookup("orcz"); - Config c = h.getConfig(); - String exactCase = c.getValue("StrictHostKeyChecking"); - assertEquals("yes", exactCase); - assertEquals(exactCase, c.getValue("stricthostkeychecking")); - assertEquals(exactCase, c.getValue("STRICTHOSTKEYCHECKING")); - assertEquals(exactCase, c.getValue("sTrIcThostKEYcheckING")); - assertNull(c.getValue("sTrIcThostKEYcheckIN")); - } - - @Test - public void testAlias_DoesNotMatch() throws Exception { - config("Host orcz\n" + "Port 29418\n" + "\tHostName repo.or.cz\n"); - final Host h = osc.lookup("repo.or.cz"); - assertNotNull(h); - assertEquals("repo.or.cz", h.getHostName()); - assertEquals("jex_junit", h.getUser()); - assertEquals(22, h.getPort()); - assertNull(h.getIdentityFile()); - final Host h2 = osc.lookup("orcz"); - assertEquals("repo.or.cz", h.getHostName()); - assertEquals("jex_junit", h.getUser()); - assertEquals(29418, h2.getPort()); - assertNull(h.getIdentityFile()); - } - - @Test - public void testAlias_OptionsSet() throws Exception { - config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\tPort 2222\n" - + "\tUser jex\n" + "\tIdentityFile .ssh/id_jex\n" - + "\tForwardX11 no\n"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals("repo.or.cz", h.getHostName()); - assertEquals("jex", h.getUser()); - assertEquals(2222, h.getPort()); - assertEquals(new File(home, ".ssh/id_jex"), h.getIdentityFile()); - } - - @Test - public void testAlias_OptionsKeywordCaseInsensitive() throws Exception { - config("hOsT orcz\n" + "\thOsTnAmE repo.or.cz\n" + "\tPORT 2222\n" - + "\tuser jex\n" + "\tidentityfile .ssh/id_jex\n" - + "\tForwardX11 no\n"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals("repo.or.cz", h.getHostName()); - assertEquals("jex", h.getUser()); - assertEquals(2222, h.getPort()); - assertEquals(new File(home, ".ssh/id_jex"), h.getIdentityFile()); - } - - @Test - public void testAlias_OptionsInherit() throws Exception { - config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n" - + "\tHostName not.a.host.example.com\n" + "\tPort 2222\n" - + "\tUser jex\n" + "\tIdentityFile .ssh/id_jex\n" - + "\tForwardX11 no\n"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals("repo.or.cz", h.getHostName()); - assertEquals("jex", h.getUser()); - assertEquals(2222, h.getPort()); - assertEquals(new File(home, ".ssh/id_jex"), h.getIdentityFile()); - } - - @Test - public void testAlias_PreferredAuthenticationsDefault() throws Exception { - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertNull(h.getPreferredAuthentications()); - } - - @Test - public void testAlias_PreferredAuthentications() throws Exception { - config("Host orcz\n" + "\tPreferredAuthentications publickey\n"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals("publickey", h.getPreferredAuthentications()); - } - - @Test - public void testAlias_InheritPreferredAuthentications() throws Exception { - config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n" - + "\tPreferredAuthentications publickey, hostbased\n"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals("publickey,hostbased", h.getPreferredAuthentications()); - } - - @Test - public void testAlias_BatchModeDefault() throws Exception { - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertFalse(h.isBatchMode()); - } - - @Test - public void testAlias_BatchModeYes() throws Exception { - config("Host orcz\n" + "\tBatchMode yes\n"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertTrue(h.isBatchMode()); - } - - @Test - public void testAlias_InheritBatchMode() throws Exception { - config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n" - + "\tBatchMode yes\n"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertTrue(h.isBatchMode()); - } - - @Test - public void testAlias_ConnectionAttemptsDefault() throws Exception { - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals(1, h.getConnectionAttempts()); - } - - @Test - public void testAlias_ConnectionAttempts() throws Exception { - config("Host orcz\n" + "\tConnectionAttempts 5\n"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals(5, h.getConnectionAttempts()); - } - - @Test - public void testAlias_invalidConnectionAttempts() throws Exception { - config("Host orcz\n" + "\tConnectionAttempts -1\n"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals(1, h.getConnectionAttempts()); - } - - @Test - public void testAlias_badConnectionAttempts() throws Exception { - config("Host orcz\n" + "\tConnectionAttempts xxx\n"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals(1, h.getConnectionAttempts()); - } - - @Test - public void testDefaultBlock() throws Exception { - config("ConnectionAttempts 5\n\nHost orcz\nConnectionAttempts 3\n"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals(5, h.getConnectionAttempts()); - } - - @Test - public void testHostCaseInsensitive() throws Exception { - config("hOsT orcz\nConnectionAttempts 3\n"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals(3, h.getConnectionAttempts()); - } - - @Test - public void testListValueSingle() throws Exception { - config("Host orcz\nUserKnownHostsFile /foo/bar\n"); - final ConfigRepository.Config c = osc.getConfig("orcz"); - assertNotNull(c); - assertEquals("/foo/bar", c.getValue("UserKnownHostsFile")); - } - - @Test - public void testListValueMultiple() throws Exception { - // Tilde expansion occurs within the parser - config("Host orcz\nUserKnownHostsFile \"~/foo/ba z\" /foo/bar \n"); - final ConfigRepository.Config c = osc.getConfig("orcz"); - assertNotNull(c); - assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(), - "/foo/bar" }, - c.getValues("UserKnownHostsFile")); - } - - @Test - public void testRepeatedLookupsWithModification() throws Exception { - config("Host orcz\n" + "\tConnectionAttempts -1\n"); - final Host h1 = osc.lookup("orcz"); - assertNotNull(h1); - assertEquals(1, h1.getConnectionAttempts()); - config("Host orcz\n" + "\tConnectionAttempts 5\n"); - final Host h2 = osc.lookup("orcz"); - assertNotNull(h2); - assertNotSame(h1, h2); - assertEquals(5, h2.getConnectionAttempts()); - assertEquals(1, h1.getConnectionAttempts()); - assertNotSame(h1.getConfig(), h2.getConfig()); - } - - @Test - public void testIdentityFile() throws Exception { - config("Host orcz\nIdentityFile \"~/foo/ba z\"\nIdentityFile /foo/bar"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - File f = h.getIdentityFile(); - assertNotNull(f); - // Host does tilde replacement - assertEquals(new File(home, "foo/ba z"), f); - final ConfigRepository.Config c = h.getConfig(); - // Config does tilde replacement, too - assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(), - "/foo/bar" }, - c.getValues("IdentityFile")); - } - - @Test - public void testMultiIdentityFile() throws Exception { - config("IdentityFile \"~/foo/ba z\"\nHost orcz\nIdentityFile /foo/bar\nHOST *\nIdentityFile /foo/baz"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - File f = h.getIdentityFile(); - assertNotNull(f); - // Host does tilde replacement - assertEquals(new File(home, "foo/ba z"), f); - final ConfigRepository.Config c = h.getConfig(); - // Config does tilde replacement, too - assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(), - "/foo/bar", "/foo/baz" }, - c.getValues("IdentityFile")); - } - - @Test - public void testNegatedPattern() throws Exception { - config("Host repo.or.cz\nIdentityFile ~/foo/bar\nHOST !*.or.cz\nIdentityFile /foo/baz"); - final Host h = osc.lookup("repo.or.cz"); - assertNotNull(h); - assertEquals(new File(home, "foo/bar"), h.getIdentityFile()); - assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath() }, - h.getConfig().getValues("IdentityFile")); - } - - @Test - public void testPattern() throws Exception { - config("Host repo.or.cz\nIdentityFile ~/foo/bar\nHOST *.or.cz\nIdentityFile /foo/baz"); - final Host h = osc.lookup("repo.or.cz"); - assertNotNull(h); - assertEquals(new File(home, "foo/bar"), h.getIdentityFile()); - assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath(), - "/foo/baz" }, - h.getConfig().getValues("IdentityFile")); - } - - @Test - public void testMultiHost() throws Exception { - config("Host orcz *.or.cz\nIdentityFile ~/foo/bar\nHOST *.or.cz\nIdentityFile /foo/baz"); - final Host h1 = osc.lookup("repo.or.cz"); - assertNotNull(h1); - assertEquals(new File(home, "foo/bar"), h1.getIdentityFile()); - assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath(), - "/foo/baz" }, - h1.getConfig().getValues("IdentityFile")); - final Host h2 = osc.lookup("orcz"); - assertNotNull(h2); - assertEquals(new File(home, "foo/bar"), h2.getIdentityFile()); - assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath() }, - h2.getConfig().getValues("IdentityFile")); - } - - @Test - public void testEqualsSign() throws Exception { - config("Host=orcz\n\tConnectionAttempts = 5\n\tUser=\t foobar\t\n"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals(5, h.getConnectionAttempts()); - assertEquals("foobar", h.getUser()); - } - - @Test - public void testMissingArgument() throws Exception { - config("Host=orcz\n\tSendEnv\nIdentityFile\t\nForwardX11\n\tUser=\t foobar\t\n"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals("foobar", h.getUser()); - assertArrayEquals(new String[0], h.getConfig().getValues("SendEnv")); - assertNull(h.getIdentityFile()); - assertNull(h.getConfig().getValue("ForwardX11")); - } - - @Test - public void testHomeDirUserReplacement() throws Exception { - config("Host=orcz\n\tIdentityFile %d/.ssh/%u_id_dsa"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals(new File(new File(home, ".ssh"), "jex_junit_id_dsa"), - h.getIdentityFile()); - } - - @Test - public void testHostnameReplacement() throws Exception { - config("Host=orcz\nHost *.*\n\tHostname %h\nHost *\n\tHostname %h.example.org"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals("orcz.example.org", h.getHostName()); - } - - @Test - public void testRemoteUserReplacement() throws Exception { - config("Host=orcz\n\tUser foo\n" + "Host *.*\n\tHostname %h\n" - + "Host *\n\tHostname %h.ex%%20ample.org\n\tIdentityFile ~/.ssh/%h_%r_id_dsa"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals( - new File(new File(home, ".ssh"), - "orcz.ex%20ample.org_foo_id_dsa"), - h.getIdentityFile()); - } - - @Test - public void testLocalhostFQDNReplacement() throws Exception { - String localhost = SystemReader.getInstance().getHostname(); - config("Host=orcz\n\tIdentityFile ~/.ssh/%l_id_dsa"); - final Host h = osc.lookup("orcz"); - assertNotNull(h); - assertEquals( - new File(new File(home, ".ssh"), localhost + "_id_dsa"), - h.getIdentityFile()); - } - - @Test - public void testPubKeyAcceptedAlgorithms() throws Exception { - config("Host=orcz\n\tPubkeyAcceptedAlgorithms ^ssh-rsa"); - Host h = osc.lookup("orcz"); - Config c = h.getConfig(); - assertEquals("^ssh-rsa", - c.getValue(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS)); - assertEquals("^ssh-rsa", c.getValue("PubkeyAcceptedKeyTypes")); - } - - @Test - public void testPubKeyAcceptedKeyTypes() throws Exception { - config("Host=orcz\n\tPubkeyAcceptedKeyTypes ^ssh-rsa"); - Host h = osc.lookup("orcz"); - Config c = h.getConfig(); - assertEquals("^ssh-rsa", - c.getValue(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS)); - assertEquals("^ssh-rsa", c.getValue("PubkeyAcceptedKeyTypes")); - } - - @Test - public void testEolComments() throws Exception { - config("#Comment\nHost=orcz #Comment\n\tPubkeyAcceptedAlgorithms ^ssh-rsa # Comment\n#Comment"); - Host h = osc.lookup("orcz"); - assertNotNull(h); - Config c = h.getConfig(); - assertEquals("^ssh-rsa", - c.getValue(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS)); - } - - @Test - public void testEnVarSubstitution() throws Exception { - config("Host orcz\nIdentityFile /tmp/${TST_VAR}\n" - + "CertificateFile /tmp/${}/foo\nUser ${TST_VAR}\nIdentityAgent /tmp/${TST_VAR/bar"); - Host h = osc.lookup("orcz"); - assertNotNull(h); - Config c = h.getConfig(); - assertEquals("/tmp/TEST", - c.getValue(SshConstants.IDENTITY_FILE)); - // No variable name - assertEquals("/tmp/${}/foo", c.getValue(SshConstants.CERTIFICATE_FILE)); - // User doesn't get env var substitution: - assertEquals("${TST_VAR}", c.getValue(SshConstants.USER)); - assertEquals("${TST_VAR}", h.getUser()); - // Unterminated: - assertEquals("/tmp/${TST_VAR/bar", - c.getValue(SshConstants.IDENTITY_AGENT)); - } - - @Test - public void testNegativeMatch() throws Exception { - config("Host foo.bar !foobar.baz *.baz\n" + "Port 29418\n"); - Host h = osc.lookup("foo.bar"); - assertNotNull(h); - assertEquals(29418, h.getPort()); - h = osc.lookup("foobar.baz"); - assertNotNull(h); - assertEquals(22, h.getPort()); - h = osc.lookup("foo.baz"); - assertNotNull(h); - assertEquals(29418, h.getPort()); - } - - @Test - public void testNegativeMatch2() throws Exception { - // Negative match after the positive match. - config("Host foo.bar *.baz !foobar.baz\n" + "Port 29418\n"); - Host h = osc.lookup("foo.bar"); - assertNotNull(h); - assertEquals(29418, h.getPort()); - h = osc.lookup("foobar.baz"); - assertNotNull(h); - assertEquals(22, h.getPort()); - h = osc.lookup("foo.baz"); - assertNotNull(h); - assertEquals(29418, h.getPort()); - } - - @Test - public void testNoMatch() throws Exception { - config("Host !host1 !host2\n" + "Port 29418\n"); - Host h = osc.lookup("host1"); - assertNotNull(h); - assertEquals(22, h.getPort()); - h = osc.lookup("host2"); - assertNotNull(h); - assertEquals(22, h.getPort()); - h = osc.lookup("host3"); - assertNotNull(h); - assertEquals(22, h.getPort()); - } - - @Test - public void testMultipleMatch() throws Exception { - config("Host foo.bar\nPort 29418\nIdentityFile /foo\n\n" - + "Host *.bar\nPort 22\nIdentityFile /bar\n" - + "Host foo.bar\nPort 47\nIdentityFile /baz\n"); - Host h = osc.lookup("foo.bar"); - assertNotNull(h); - assertEquals(29418, h.getPort()); - assertArrayEquals(new Object[] { "/foo", "/bar", "/baz" }, - h.getConfig().getValues("IdentityFile")); - } - - @Test - public void testWhitespace() throws Exception { - config("Host foo \tbar baz\nPort 29418\n"); - Host h = osc.lookup("foo"); - assertNotNull(h); - assertEquals(29418, h.getPort()); - h = osc.lookup("bar"); - assertNotNull(h); - assertEquals(29418, h.getPort()); - h = osc.lookup("baz"); - assertNotNull(h); - assertEquals(29418, h.getPort()); - h = osc.lookup("\tbar"); - assertNotNull(h); - assertEquals(22, h.getPort()); - } -} diff --git a/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JSchSshProtocol2Test.java b/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JSchSshProtocol2Test.java new file mode 100644 index 0000000000..611d4e8bcb --- /dev/null +++ b/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JSchSshProtocol2Test.java @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2020 Thomas Wolf and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +//TODO(ms): move to org.eclipse.jgit.ssh.jsch in 6.0 +package org.eclipse.jgit.transport.ssh.jsch; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.util.Arrays; + +import org.eclipse.jgit.errors.TransportException; +import org.eclipse.jgit.junit.ssh.SshBasicTestBase; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.lib.StoredConfig; +import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.RemoteSession; +import org.eclipse.jgit.transport.SshSessionFactory; +import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.transport.ssh.jsch.OpenSshConfig.Host; +import org.eclipse.jgit.util.FS; + +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; + +public class JSchSshProtocol2Test extends SshBasicTestBase { + + private class TestSshSessionFactory extends JschConfigSessionFactory { + + @Override + protected void configure(Host hc, Session session) { + // Nothing + } + + @Override + public synchronized RemoteSession getSession(URIish uri, + CredentialsProvider credentialsProvider, FS fs, int tms) + throws TransportException { + return super.getSession(uri, credentialsProvider, fs, tms); + } + + @Override + protected JSch createDefaultJSch(FS fs) throws JSchException { + JSch defaultJSch = super.createDefaultJSch(fs); + if (knownHosts.exists()) { + defaultJSch.setKnownHosts(knownHosts.getAbsolutePath()); + } + return defaultJSch; + } + } + + @Override + protected SshSessionFactory createSessionFactory() { + return new TestSshSessionFactory(); + } + + @Override + protected void installConfig(String... config) { + SshSessionFactory factory = getSessionFactory(); + assertTrue(factory instanceof JschConfigSessionFactory); + JschConfigSessionFactory j = (JschConfigSessionFactory) factory; + try { + j.setConfig(createConfig(config)); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private OpenSshConfig createConfig(String... content) throws IOException { + File configFile = new File(sshDir, Constants.CONFIG); + if (content != null) { + Files.write(configFile.toPath(), Arrays.asList(content)); + } + return new OpenSshConfig(getTemporaryDirectory(), configFile); + } + + @Override + public void setUp() throws Exception { + super.setUp(); + StoredConfig config = ((Repository) db).getConfig(); + config.setInt("protocol", null, "version", 2); + config.save(); + } +} diff --git a/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JSchSshTest.java b/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JSchSshTest.java new file mode 100644 index 0000000000..54cb84b2f7 --- /dev/null +++ b/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JSchSshTest.java @@ -0,0 +1,89 @@ +/* + * Copyright (C) 2018, Thomas Wolf and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.transport.ssh.jsch; + +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.IOException; +import java.io.UncheckedIOException; +import java.nio.file.Files; +import java.util.Arrays; + +import org.eclipse.jgit.errors.TransportException; +import org.eclipse.jgit.junit.ssh.SshTestBase; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.transport.CredentialsProvider; +import org.eclipse.jgit.transport.RemoteSession; +import org.eclipse.jgit.transport.SshSessionFactory; +import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.transport.ssh.jsch.OpenSshConfig.Host; +import org.eclipse.jgit.util.FS; +import org.junit.experimental.theories.Theories; +import org.junit.runner.RunWith; + +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; + +@RunWith(Theories.class) +public class JSchSshTest extends SshTestBase { + + private class TestSshSessionFactory extends JschConfigSessionFactory { + + @Override + protected void configure(Host hc, Session session) { + // Nothing + } + + @Override + public synchronized RemoteSession getSession(URIish uri, + CredentialsProvider credentialsProvider, FS fs, int tms) + throws TransportException { + return super.getSession(uri, credentialsProvider, fs, tms); + } + + @Override + protected JSch createDefaultJSch(FS fs) throws JSchException { + JSch defaultJSch = super.createDefaultJSch(fs); + if (knownHosts.exists()) { + defaultJSch.setKnownHosts(knownHosts.getAbsolutePath()); + } + return defaultJSch; + } + } + + @Override + protected SshSessionFactory createSessionFactory() { + return new TestSshSessionFactory(); + } + + @Override + protected void installConfig(String... config) { + SshSessionFactory factory = getSessionFactory(); + assertTrue(factory instanceof JschConfigSessionFactory); + JschConfigSessionFactory j = (JschConfigSessionFactory) factory; + try { + j.setConfig(createConfig(config)); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + } + + private OpenSshConfig createConfig(String... content) throws IOException { + File configFile = new File(sshDir, Constants.CONFIG); + if (content != null) { + Files.write(configFile.toPath(), Arrays.asList(content)); + } + return new OpenSshConfig(getTemporaryDirectory(), configFile); + } + +} diff --git a/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JschConfigSessionFactoryTest.java b/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JschConfigSessionFactoryTest.java new file mode 100644 index 0000000000..4309bedba9 --- /dev/null +++ b/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/JschConfigSessionFactoryTest.java @@ -0,0 +1,263 @@ +/* + * Copyright (C) 2018, Thomas Wolf and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +//TODO(ms): move to org.eclipse.jgit.ssh.jsch in 6.0 +package org.eclipse.jgit.transport.ssh.jsch; + +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.junit.MockSystemReader; +import org.eclipse.jgit.transport.URIish; +import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.SystemReader; +import org.junit.After; +import org.junit.Before; +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; + + JschConfigSessionFactory factory = new JschConfigSessionFactory(); + + @Before + public void setup() { + SystemReader.setInstance(new MockSystemReader()); + } + + @After + public void removeTmpConfig() { + SystemReader.setInstance(null); + 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(SystemReader.getInstance().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()); + } + + @Test + public void testAliasCaseDifferenceUpcase() throws Exception { + tmpConfigFile = createConfig("Host Bitbucket.org", + "Hostname bitbucket.org", "User foo", "Port 29418", + "ConnectTimeout 10", // + "Host bitbucket.org", "Hostname bitbucket.org", "User bar", + "Port 22", "ConnectTimeout 5"); + tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(), + tmpConfigFile); + factory.setConfig(tmpConfig); + Session session = createSession("ssh://Bitbucket.org/something"); + assertEquals("bitbucket.org", session.getHost()); + assertEquals("foo", session.getUserName()); + assertEquals(29418, session.getPort()); + assertEquals(TimeUnit.SECONDS.toMillis(10), session.getTimeout()); + } + + @Test + public void testAliasCaseDifferenceLowcase() throws Exception { + tmpConfigFile = createConfig("Host Bitbucket.org", + "Hostname bitbucket.org", "User foo", "Port 29418", + "ConnectTimeout 10", // + "Host bitbucket.org", "Hostname bitbucket.org", "User bar", + "Port 22", "ConnectTimeout 5"); + tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(), + tmpConfigFile); + factory.setConfig(tmpConfig); + Session session = createSession("ssh://bitbucket.org/something"); + assertEquals("bitbucket.org", session.getHost()); + assertEquals("bar", session.getUserName()); + assertEquals(22, session.getPort()); + assertEquals(TimeUnit.SECONDS.toMillis(5), session.getTimeout()); + } + + @Test + public void testAliasCaseDifferenceUpcaseInverted() throws Exception { + tmpConfigFile = createConfig("Host bitbucket.org", + "Hostname bitbucket.org", "User bar", "Port 22", + "ConnectTimeout 5", // + "Host Bitbucket.org", "Hostname bitbucket.org", "User foo", + "Port 29418", "ConnectTimeout 10"); + tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(), + tmpConfigFile); + factory.setConfig(tmpConfig); + Session session = createSession("ssh://Bitbucket.org/something"); + assertEquals("bitbucket.org", session.getHost()); + assertEquals("foo", session.getUserName()); + assertEquals(29418, session.getPort()); + assertEquals(TimeUnit.SECONDS.toMillis(10), session.getTimeout()); + } + + @Test + public void testAliasCaseDifferenceLowcaseInverted() throws Exception { + tmpConfigFile = createConfig("Host bitbucket.org", + "Hostname bitbucket.org", "User bar", "Port 22", + "ConnectTimeout 5", // + "Host Bitbucket.org", "Hostname bitbucket.org", "User foo", + "Port 29418", "ConnectTimeout 10"); + tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(), + tmpConfigFile); + factory.setConfig(tmpConfig); + Session session = createSession("ssh://bitbucket.org/something"); + assertEquals("bitbucket.org", session.getHost()); + assertEquals("bar", session.getUserName()); + assertEquals(22, session.getPort()); + assertEquals(TimeUnit.SECONDS.toMillis(5), 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); + if (port <= 0) { + port = hostConfig.getPort(); + } + if (user == null) { + user = hostConfig.getUser(); + } + return factory.createSession(null, FS.DETECTED, user, password, host, + port, hostConfig); + } +} diff --git a/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/OpenSshConfigTest.java b/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/OpenSshConfigTest.java new file mode 100644 index 0000000000..4399ad9be6 --- /dev/null +++ b/org.eclipse.jgit.ssh.jsch.test/tst/org/eclipse/jgit/transport/ssh/jsch/OpenSshConfigTest.java @@ -0,0 +1,592 @@ +/* + * Copyright (C) 2008, 2021 Google Inc. and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +package org.eclipse.jgit.transport.ssh.jsch; + +import static java.nio.charset.StandardCharsets.UTF_8; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.time.Instant; +import java.util.concurrent.TimeUnit; + +import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.transport.SshConstants; +import org.eclipse.jgit.transport.ssh.jsch.OpenSshConfig.Host; +import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.FileUtils; +import org.eclipse.jgit.util.SystemReader; +import org.junit.Before; +import org.junit.Test; + +import com.jcraft.jsch.ConfigRepository; +import com.jcraft.jsch.ConfigRepository.Config; + +public class OpenSshConfigTest extends RepositoryTestCase { + private File home; + + private File configFile; + + private OpenSshConfig osc; + + @Override + @Before + public void setUp() throws Exception { + super.setUp(); + + home = new File(trash, "home"); + FileUtils.mkdir(home); + + configFile = new File(new File(home, ".ssh"), Constants.CONFIG); + FileUtils.mkdir(configFile.getParentFile()); + + mockSystemReader.setProperty(Constants.OS_USER_NAME_KEY, "jex_junit"); + mockSystemReader.setProperty("TST_VAR", "TEST"); + osc = new OpenSshConfig(home, configFile); + } + + private void config(String data) throws IOException { + FS fs = FS.DETECTED; + long resolution = FS.getFileStoreAttributes(configFile.toPath()) + .getFsTimestampResolution().toNanos(); + Instant lastMtime = fs.lastModifiedInstant(configFile); + do { + try (final OutputStreamWriter fw = new OutputStreamWriter( + new FileOutputStream(configFile), UTF_8)) { + fw.write(data); + TimeUnit.NANOSECONDS.sleep(resolution); + } catch (InterruptedException e) { + Thread.interrupted(); + } + } while (lastMtime.equals(fs.lastModifiedInstant(configFile))); + } + + @Test + public void testNoConfig() { + final Host h = osc.lookup("repo.or.cz"); + assertNotNull(h); + assertEquals("repo.or.cz", h.getHostName()); + assertEquals("jex_junit", h.getUser()); + assertEquals(22, h.getPort()); + assertEquals(1, h.getConnectionAttempts()); + assertNull(h.getIdentityFile()); + } + + @Test + public void testSeparatorParsing() throws Exception { + config("Host\tfirst\n" + + "\tHostName\tfirst.tld\n" + + "\n" + + "Host second\n" + + " HostName\tsecond.tld\n" + + "Host=third\n" + + "HostName=third.tld\n\n\n" + + "\t Host = fourth\n\n\n" + + " \t HostName\t=fourth.tld\n" + + "Host\t = last\n" + + "HostName \t last.tld"); + assertNotNull(osc.lookup("first")); + assertEquals("first.tld", osc.lookup("first").getHostName()); + assertNotNull(osc.lookup("second")); + assertEquals("second.tld", osc.lookup("second").getHostName()); + assertNotNull(osc.lookup("third")); + assertEquals("third.tld", osc.lookup("third").getHostName()); + assertNotNull(osc.lookup("fourth")); + assertEquals("fourth.tld", osc.lookup("fourth").getHostName()); + assertNotNull(osc.lookup("last")); + assertEquals("last.tld", osc.lookup("last").getHostName()); + } + + @Test + public void testQuoteParsing() throws Exception { + config("Host \"good\"\n" + + " HostName=\"good.tld\"\n" + + " Port=\"6007\"\n" + + " User=\"gooduser\"\n" + + "Host multiple unquoted and \"quoted\" \"hosts\"\n" + + " Port=\"2222\"\n" + + "Host \"spaced\"\n" + + "# Bad host name, but testing preservation of spaces\n" + + " HostName=\" spaced\ttld \"\n" + + "# Misbalanced quotes\n" + + "Host \"bad\"\n" + + "# OpenSSH doesn't allow this but ...\n" + + " HostName=bad.tld\"\n"); + assertEquals("good.tld", osc.lookup("good").getHostName()); + assertEquals("gooduser", osc.lookup("good").getUser()); + assertEquals(6007, osc.lookup("good").getPort()); + assertEquals(2222, osc.lookup("multiple").getPort()); + assertEquals(2222, osc.lookup("quoted").getPort()); + assertEquals(2222, osc.lookup("and").getPort()); + assertEquals(2222, osc.lookup("unquoted").getPort()); + assertEquals(2222, osc.lookup("hosts").getPort()); + assertEquals(" spaced\ttld ", osc.lookup("spaced").getHostName()); + assertEquals("bad.tld\"", osc.lookup("bad").getHostName()); + } + + @Test + public void testCaseInsensitiveKeyLookup() throws Exception { + config("Host orcz\n" + "Port 29418\n" + + "\tHostName repo.or.cz\nStrictHostKeyChecking yes\n"); + final Host h = osc.lookup("orcz"); + Config c = h.getConfig(); + String exactCase = c.getValue("StrictHostKeyChecking"); + assertEquals("yes", exactCase); + assertEquals(exactCase, c.getValue("stricthostkeychecking")); + assertEquals(exactCase, c.getValue("STRICTHOSTKEYCHECKING")); + assertEquals(exactCase, c.getValue("sTrIcThostKEYcheckING")); + assertNull(c.getValue("sTrIcThostKEYcheckIN")); + } + + @Test + public void testAlias_DoesNotMatch() throws Exception { + config("Host orcz\n" + "Port 29418\n" + "\tHostName repo.or.cz\n"); + final Host h = osc.lookup("repo.or.cz"); + assertNotNull(h); + assertEquals("repo.or.cz", h.getHostName()); + assertEquals("jex_junit", h.getUser()); + assertEquals(22, h.getPort()); + assertNull(h.getIdentityFile()); + final Host h2 = osc.lookup("orcz"); + assertEquals("repo.or.cz", h.getHostName()); + assertEquals("jex_junit", h.getUser()); + assertEquals(29418, h2.getPort()); + assertNull(h.getIdentityFile()); + } + + @Test + public void testAlias_OptionsSet() throws Exception { + config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\tPort 2222\n" + + "\tUser jex\n" + "\tIdentityFile .ssh/id_jex\n" + + "\tForwardX11 no\n"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals("repo.or.cz", h.getHostName()); + assertEquals("jex", h.getUser()); + assertEquals(2222, h.getPort()); + assertEquals(new File(home, ".ssh/id_jex"), h.getIdentityFile()); + } + + @Test + public void testAlias_OptionsKeywordCaseInsensitive() throws Exception { + config("hOsT orcz\n" + "\thOsTnAmE repo.or.cz\n" + "\tPORT 2222\n" + + "\tuser jex\n" + "\tidentityfile .ssh/id_jex\n" + + "\tForwardX11 no\n"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals("repo.or.cz", h.getHostName()); + assertEquals("jex", h.getUser()); + assertEquals(2222, h.getPort()); + assertEquals(new File(home, ".ssh/id_jex"), h.getIdentityFile()); + } + + @Test + public void testAlias_OptionsInherit() throws Exception { + config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n" + + "\tHostName not.a.host.example.com\n" + "\tPort 2222\n" + + "\tUser jex\n" + "\tIdentityFile .ssh/id_jex\n" + + "\tForwardX11 no\n"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals("repo.or.cz", h.getHostName()); + assertEquals("jex", h.getUser()); + assertEquals(2222, h.getPort()); + assertEquals(new File(home, ".ssh/id_jex"), h.getIdentityFile()); + } + + @Test + public void testAlias_PreferredAuthenticationsDefault() throws Exception { + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertNull(h.getPreferredAuthentications()); + } + + @Test + public void testAlias_PreferredAuthentications() throws Exception { + config("Host orcz\n" + "\tPreferredAuthentications publickey\n"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals("publickey", h.getPreferredAuthentications()); + } + + @Test + public void testAlias_InheritPreferredAuthentications() throws Exception { + config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n" + + "\tPreferredAuthentications publickey, hostbased\n"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals("publickey,hostbased", h.getPreferredAuthentications()); + } + + @Test + public void testAlias_BatchModeDefault() throws Exception { + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertFalse(h.isBatchMode()); + } + + @Test + public void testAlias_BatchModeYes() throws Exception { + config("Host orcz\n" + "\tBatchMode yes\n"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertTrue(h.isBatchMode()); + } + + @Test + public void testAlias_InheritBatchMode() throws Exception { + config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n" + + "\tBatchMode yes\n"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertTrue(h.isBatchMode()); + } + + @Test + public void testAlias_ConnectionAttemptsDefault() throws Exception { + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals(1, h.getConnectionAttempts()); + } + + @Test + public void testAlias_ConnectionAttempts() throws Exception { + config("Host orcz\n" + "\tConnectionAttempts 5\n"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals(5, h.getConnectionAttempts()); + } + + @Test + public void testAlias_invalidConnectionAttempts() throws Exception { + config("Host orcz\n" + "\tConnectionAttempts -1\n"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals(1, h.getConnectionAttempts()); + } + + @Test + public void testAlias_badConnectionAttempts() throws Exception { + config("Host orcz\n" + "\tConnectionAttempts xxx\n"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals(1, h.getConnectionAttempts()); + } + + @Test + public void testDefaultBlock() throws Exception { + config("ConnectionAttempts 5\n\nHost orcz\nConnectionAttempts 3\n"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals(5, h.getConnectionAttempts()); + } + + @Test + public void testHostCaseInsensitive() throws Exception { + config("hOsT orcz\nConnectionAttempts 3\n"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals(3, h.getConnectionAttempts()); + } + + @Test + public void testListValueSingle() throws Exception { + config("Host orcz\nUserKnownHostsFile /foo/bar\n"); + final ConfigRepository.Config c = osc.getConfig("orcz"); + assertNotNull(c); + assertEquals("/foo/bar", c.getValue("UserKnownHostsFile")); + } + + @Test + public void testListValueMultiple() throws Exception { + // Tilde expansion occurs within the parser + config("Host orcz\nUserKnownHostsFile \"~/foo/ba z\" /foo/bar \n"); + final ConfigRepository.Config c = osc.getConfig("orcz"); + assertNotNull(c); + assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(), + "/foo/bar" }, + c.getValues("UserKnownHostsFile")); + } + + @Test + public void testRepeatedLookupsWithModification() throws Exception { + config("Host orcz\n" + "\tConnectionAttempts -1\n"); + final Host h1 = osc.lookup("orcz"); + assertNotNull(h1); + assertEquals(1, h1.getConnectionAttempts()); + config("Host orcz\n" + "\tConnectionAttempts 5\n"); + final Host h2 = osc.lookup("orcz"); + assertNotNull(h2); + assertNotSame(h1, h2); + assertEquals(5, h2.getConnectionAttempts()); + assertEquals(1, h1.getConnectionAttempts()); + assertNotSame(h1.getConfig(), h2.getConfig()); + } + + @Test + public void testIdentityFile() throws Exception { + config("Host orcz\nIdentityFile \"~/foo/ba z\"\nIdentityFile /foo/bar"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + File f = h.getIdentityFile(); + assertNotNull(f); + // Host does tilde replacement + assertEquals(new File(home, "foo/ba z"), f); + final ConfigRepository.Config c = h.getConfig(); + // Config does tilde replacement, too + assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(), + "/foo/bar" }, + c.getValues("IdentityFile")); + } + + @Test + public void testMultiIdentityFile() throws Exception { + config("IdentityFile \"~/foo/ba z\"\nHost orcz\nIdentityFile /foo/bar\nHOST *\nIdentityFile /foo/baz"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + File f = h.getIdentityFile(); + assertNotNull(f); + // Host does tilde replacement + assertEquals(new File(home, "foo/ba z"), f); + final ConfigRepository.Config c = h.getConfig(); + // Config does tilde replacement, too + assertArrayEquals(new Object[] { new File(home, "foo/ba z").getPath(), + "/foo/bar", "/foo/baz" }, + c.getValues("IdentityFile")); + } + + @Test + public void testNegatedPattern() throws Exception { + config("Host repo.or.cz\nIdentityFile ~/foo/bar\nHOST !*.or.cz\nIdentityFile /foo/baz"); + final Host h = osc.lookup("repo.or.cz"); + assertNotNull(h); + assertEquals(new File(home, "foo/bar"), h.getIdentityFile()); + assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath() }, + h.getConfig().getValues("IdentityFile")); + } + + @Test + public void testPattern() throws Exception { + config("Host repo.or.cz\nIdentityFile ~/foo/bar\nHOST *.or.cz\nIdentityFile /foo/baz"); + final Host h = osc.lookup("repo.or.cz"); + assertNotNull(h); + assertEquals(new File(home, "foo/bar"), h.getIdentityFile()); + assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath(), + "/foo/baz" }, + h.getConfig().getValues("IdentityFile")); + } + + @Test + public void testMultiHost() throws Exception { + config("Host orcz *.or.cz\nIdentityFile ~/foo/bar\nHOST *.or.cz\nIdentityFile /foo/baz"); + final Host h1 = osc.lookup("repo.or.cz"); + assertNotNull(h1); + assertEquals(new File(home, "foo/bar"), h1.getIdentityFile()); + assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath(), + "/foo/baz" }, + h1.getConfig().getValues("IdentityFile")); + final Host h2 = osc.lookup("orcz"); + assertNotNull(h2); + assertEquals(new File(home, "foo/bar"), h2.getIdentityFile()); + assertArrayEquals(new Object[] { new File(home, "foo/bar").getPath() }, + h2.getConfig().getValues("IdentityFile")); + } + + @Test + public void testEqualsSign() throws Exception { + config("Host=orcz\n\tConnectionAttempts = 5\n\tUser=\t foobar\t\n"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals(5, h.getConnectionAttempts()); + assertEquals("foobar", h.getUser()); + } + + @Test + public void testMissingArgument() throws Exception { + config("Host=orcz\n\tSendEnv\nIdentityFile\t\nForwardX11\n\tUser=\t foobar\t\n"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals("foobar", h.getUser()); + assertArrayEquals(new String[0], h.getConfig().getValues("SendEnv")); + assertNull(h.getIdentityFile()); + assertNull(h.getConfig().getValue("ForwardX11")); + } + + @Test + public void testHomeDirUserReplacement() throws Exception { + config("Host=orcz\n\tIdentityFile %d/.ssh/%u_id_dsa"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals(new File(new File(home, ".ssh"), "jex_junit_id_dsa"), + h.getIdentityFile()); + } + + @Test + public void testHostnameReplacement() throws Exception { + config("Host=orcz\nHost *.*\n\tHostname %h\nHost *\n\tHostname %h.example.org"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals("orcz.example.org", h.getHostName()); + } + + @Test + public void testRemoteUserReplacement() throws Exception { + config("Host=orcz\n\tUser foo\n" + "Host *.*\n\tHostname %h\n" + + "Host *\n\tHostname %h.ex%%20ample.org\n\tIdentityFile ~/.ssh/%h_%r_id_dsa"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals( + new File(new File(home, ".ssh"), + "orcz.ex%20ample.org_foo_id_dsa"), + h.getIdentityFile()); + } + + @Test + public void testLocalhostFQDNReplacement() throws Exception { + String localhost = SystemReader.getInstance().getHostname(); + config("Host=orcz\n\tIdentityFile ~/.ssh/%l_id_dsa"); + final Host h = osc.lookup("orcz"); + assertNotNull(h); + assertEquals( + new File(new File(home, ".ssh"), localhost + "_id_dsa"), + h.getIdentityFile()); + } + + @Test + public void testPubKeyAcceptedAlgorithms() throws Exception { + config("Host=orcz\n\tPubkeyAcceptedAlgorithms ^ssh-rsa"); + Host h = osc.lookup("orcz"); + Config c = h.getConfig(); + assertEquals("^ssh-rsa", + c.getValue(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS)); + assertEquals("^ssh-rsa", c.getValue("PubkeyAcceptedKeyTypes")); + } + + @Test + public void testPubKeyAcceptedKeyTypes() throws Exception { + config("Host=orcz\n\tPubkeyAcceptedKeyTypes ^ssh-rsa"); + Host h = osc.lookup("orcz"); + Config c = h.getConfig(); + assertEquals("^ssh-rsa", + c.getValue(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS)); + assertEquals("^ssh-rsa", c.getValue("PubkeyAcceptedKeyTypes")); + } + + @Test + public void testEolComments() throws Exception { + config("#Comment\nHost=orcz #Comment\n\tPubkeyAcceptedAlgorithms ^ssh-rsa # Comment\n#Comment"); + Host h = osc.lookup("orcz"); + assertNotNull(h); + Config c = h.getConfig(); + assertEquals("^ssh-rsa", + c.getValue(SshConstants.PUBKEY_ACCEPTED_ALGORITHMS)); + } + + @Test + public void testEnVarSubstitution() throws Exception { + config("Host orcz\nIdentityFile /tmp/${TST_VAR}\n" + + "CertificateFile /tmp/${}/foo\nUser ${TST_VAR}\nIdentityAgent /tmp/${TST_VAR/bar"); + Host h = osc.lookup("orcz"); + assertNotNull(h); + Config c = h.getConfig(); + assertEquals("/tmp/TEST", + c.getValue(SshConstants.IDENTITY_FILE)); + // No variable name + assertEquals("/tmp/${}/foo", c.getValue(SshConstants.CERTIFICATE_FILE)); + // User doesn't get env var substitution: + assertEquals("${TST_VAR}", c.getValue(SshConstants.USER)); + assertEquals("${TST_VAR}", h.getUser()); + // Unterminated: + assertEquals("/tmp/${TST_VAR/bar", + c.getValue(SshConstants.IDENTITY_AGENT)); + } + + @Test + public void testNegativeMatch() throws Exception { + config("Host foo.bar !foobar.baz *.baz\n" + "Port 29418\n"); + Host h = osc.lookup("foo.bar"); + assertNotNull(h); + assertEquals(29418, h.getPort()); + h = osc.lookup("foobar.baz"); + assertNotNull(h); + assertEquals(22, h.getPort()); + h = osc.lookup("foo.baz"); + assertNotNull(h); + assertEquals(29418, h.getPort()); + } + + @Test + public void testNegativeMatch2() throws Exception { + // Negative match after the positive match. + config("Host foo.bar *.baz !foobar.baz\n" + "Port 29418\n"); + Host h = osc.lookup("foo.bar"); + assertNotNull(h); + assertEquals(29418, h.getPort()); + h = osc.lookup("foobar.baz"); + assertNotNull(h); + assertEquals(22, h.getPort()); + h = osc.lookup("foo.baz"); + assertNotNull(h); + assertEquals(29418, h.getPort()); + } + + @Test + public void testNoMatch() throws Exception { + config("Host !host1 !host2\n" + "Port 29418\n"); + Host h = osc.lookup("host1"); + assertNotNull(h); + assertEquals(22, h.getPort()); + h = osc.lookup("host2"); + assertNotNull(h); + assertEquals(22, h.getPort()); + h = osc.lookup("host3"); + assertNotNull(h); + assertEquals(22, h.getPort()); + } + + @Test + public void testMultipleMatch() throws Exception { + config("Host foo.bar\nPort 29418\nIdentityFile /foo\n\n" + + "Host *.bar\nPort 22\nIdentityFile /bar\n" + + "Host foo.bar\nPort 47\nIdentityFile /baz\n"); + Host h = osc.lookup("foo.bar"); + assertNotNull(h); + assertEquals(29418, h.getPort()); + assertArrayEquals(new Object[] { "/foo", "/bar", "/baz" }, + h.getConfig().getValues("IdentityFile")); + } + + @Test + public void testWhitespace() throws Exception { + config("Host foo \tbar baz\nPort 29418\n"); + Host h = osc.lookup("foo"); + assertNotNull(h); + assertEquals(29418, h.getPort()); + h = osc.lookup("bar"); + assertNotNull(h); + assertEquals(29418, h.getPort()); + h = osc.lookup("baz"); + assertNotNull(h); + assertEquals(29418, h.getPort()); + h = osc.lookup("\tbar"); + assertNotNull(h); + assertEquals(22, h.getPort()); + } +} -- cgit v1.2.3