View Javadoc
1   /*
2    * Copyright (C) 2018, Thomas Wolf <thomas.wolf@paranor.ch>
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  package org.eclipse.jgit.transport;
44  
45  import static org.junit.Assert.assertEquals;
46  
47  import java.io.File;
48  import java.nio.file.Files;
49  import java.util.Arrays;
50  import java.util.concurrent.TimeUnit;
51  
52  import org.eclipse.jgit.util.FS;
53  import org.junit.After;
54  import org.junit.Test;
55  
56  import com.jcraft.jsch.Session;
57  
58  /**
59   * Tests for correctly interpreting ssh config values when Jsch sessions are
60   * used.
61   */
62  public class JschConfigSessionFactoryTest {
63  
64  	File tmpConfigFile;
65  
66  	OpenSshConfig tmpConfig;
67  
68  	DefaultSshSessionFactory factory = new DefaultSshSessionFactory();
69  
70  	@After
71  	public void removeTmpConfig() {
72  		if (tmpConfigFile == null) {
73  			return;
74  		}
75  		if (tmpConfigFile.exists() && !tmpConfigFile.delete()) {
76  			tmpConfigFile.deleteOnExit();
77  		}
78  		tmpConfigFile = null;
79  	}
80  
81  	@Test
82  	public void testNoConfigEntry() throws Exception {
83  		tmpConfigFile = File.createTempFile("jsch", "test");
84  		tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
85  				tmpConfigFile);
86  		factory.setConfig(tmpConfig);
87  		Session session = createSession("ssh://egit/egit/egit");
88  		assertEquals("egit", session.getHost());
89  		// No user in URI, none in ssh config: default is OS user name
90  		assertEquals(System.getProperty("user.name"), session.getUserName());
91  		assertEquals(22, session.getPort());
92  	}
93  
94  	@Test
95  	public void testAlias() throws Exception {
96  		tmpConfigFile = createConfig("Host egit", "Hostname git.eclipse.org",
97  				"User foo", "Port 29418");
98  		tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
99  				tmpConfigFile);
100 		factory.setConfig(tmpConfig);
101 		Session session = createSession("ssh://egit/egit/egit");
102 		assertEquals("git.eclipse.org", session.getHost());
103 		assertEquals("foo", session.getUserName());
104 		assertEquals(29418, session.getPort());
105 	}
106 
107 	@Test
108 	public void testAliasWithUser() throws Exception {
109 		tmpConfigFile = createConfig("Host egit", "Hostname git.eclipse.org",
110 				"User foo", "Port 29418");
111 		tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
112 				tmpConfigFile);
113 		factory.setConfig(tmpConfig);
114 		Session session = createSession("ssh://bar@egit/egit/egit");
115 		assertEquals("git.eclipse.org", session.getHost());
116 		assertEquals("bar", session.getUserName());
117 		assertEquals(29418, session.getPort());
118 	}
119 
120 	@Test
121 	public void testAliasWithPort() throws Exception {
122 		tmpConfigFile = createConfig("Host egit", "Hostname git.eclipse.org",
123 				"User foo", "Port 29418");
124 		tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
125 				tmpConfigFile);
126 		factory.setConfig(tmpConfig);
127 		Session session = createSession("ssh://bar@egit:22/egit/egit");
128 		assertEquals("git.eclipse.org", session.getHost());
129 		assertEquals("bar", session.getUserName());
130 		assertEquals(22, session.getPort());
131 	}
132 
133 	@Test
134 	public void testAliasIdentical() throws Exception {
135 		tmpConfigFile = createConfig("Host git.eclipse.org",
136 				"Hostname git.eclipse.org", "User foo", "Port 29418");
137 		tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
138 				tmpConfigFile);
139 		factory.setConfig(tmpConfig);
140 		Session session = createSession("ssh://git.eclipse.org/egit/egit");
141 		assertEquals("git.eclipse.org", session.getHost());
142 		assertEquals("foo", session.getUserName());
143 		assertEquals(29418, session.getPort());
144 	}
145 
146 	@Test
147 	public void testAliasIdenticalWithUser() throws Exception {
148 		tmpConfigFile = createConfig("Host git.eclipse.org",
149 				"Hostname git.eclipse.org", "User foo", "Port 29418");
150 		tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
151 				tmpConfigFile);
152 		factory.setConfig(tmpConfig);
153 		Session session = createSession("ssh://bar@git.eclipse.org/egit/egit");
154 		assertEquals("git.eclipse.org", session.getHost());
155 		assertEquals("bar", session.getUserName());
156 		assertEquals(29418, session.getPort());
157 	}
158 
159 	@Test
160 	public void testAliasIdenticalWithPort() throws Exception {
161 		tmpConfigFile = createConfig("Host git.eclipse.org",
162 				"Hostname git.eclipse.org", "User foo", "Port 29418");
163 		tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
164 				tmpConfigFile);
165 		factory.setConfig(tmpConfig);
166 		Session session = createSession(
167 				"ssh://bar@git.eclipse.org:300/egit/egit");
168 		assertEquals("git.eclipse.org", session.getHost());
169 		assertEquals("bar", session.getUserName());
170 		assertEquals(300, session.getPort());
171 	}
172 
173 	@Test
174 	public void testConnectTimout() throws Exception {
175 		tmpConfigFile = createConfig("Host git.eclipse.org",
176 				"Hostname git.eclipse.org", "User foo", "Port 29418",
177 				"ConnectTimeout 10");
178 		tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
179 				tmpConfigFile);
180 		factory.setConfig(tmpConfig);
181 		Session session = createSession("ssh://git.eclipse.org/something");
182 		assertEquals("git.eclipse.org", session.getHost());
183 		assertEquals("foo", session.getUserName());
184 		assertEquals(29418, session.getPort());
185 		assertEquals(TimeUnit.SECONDS.toMillis(10), session.getTimeout());
186 	}
187 
188 	@Test
189 	public void testAliasCaseDifferenceUpcase() throws Exception {
190 		tmpConfigFile = createConfig("Host Bitbucket.org",
191 				"Hostname bitbucket.org", "User foo", "Port 29418",
192 				"ConnectTimeout 10", //
193 				"Host bitbucket.org", "Hostname bitbucket.org", "User bar",
194 				"Port 22", "ConnectTimeout 5");
195 		tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
196 				tmpConfigFile);
197 		factory.setConfig(tmpConfig);
198 		Session session = createSession("ssh://Bitbucket.org/something");
199 		assertEquals("bitbucket.org", session.getHost());
200 		assertEquals("foo", session.getUserName());
201 		assertEquals(29418, session.getPort());
202 		assertEquals(TimeUnit.SECONDS.toMillis(10), session.getTimeout());
203 	}
204 
205 	@Test
206 	public void testAliasCaseDifferenceLowcase() throws Exception {
207 		tmpConfigFile = createConfig("Host Bitbucket.org",
208 				"Hostname bitbucket.org", "User foo", "Port 29418",
209 				"ConnectTimeout 10", //
210 				"Host bitbucket.org", "Hostname bitbucket.org", "User bar",
211 				"Port 22", "ConnectTimeout 5");
212 		tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
213 				tmpConfigFile);
214 		factory.setConfig(tmpConfig);
215 		Session session = createSession("ssh://bitbucket.org/something");
216 		assertEquals("bitbucket.org", session.getHost());
217 		assertEquals("bar", session.getUserName());
218 		assertEquals(22, session.getPort());
219 		assertEquals(TimeUnit.SECONDS.toMillis(5), session.getTimeout());
220 	}
221 
222 	@Test
223 	public void testAliasCaseDifferenceUpcaseInverted() throws Exception {
224 		tmpConfigFile = createConfig("Host bitbucket.org",
225 				"Hostname bitbucket.org", "User bar", "Port 22",
226 				"ConnectTimeout 5", //
227 				"Host Bitbucket.org", "Hostname bitbucket.org", "User foo",
228 				"Port 29418", "ConnectTimeout 10");
229 		tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
230 				tmpConfigFile);
231 		factory.setConfig(tmpConfig);
232 		Session session = createSession("ssh://Bitbucket.org/something");
233 		assertEquals("bitbucket.org", session.getHost());
234 		assertEquals("foo", session.getUserName());
235 		assertEquals(29418, session.getPort());
236 		assertEquals(TimeUnit.SECONDS.toMillis(10), session.getTimeout());
237 	}
238 
239 	@Test
240 	public void testAliasCaseDifferenceLowcaseInverted() throws Exception {
241 		tmpConfigFile = createConfig("Host bitbucket.org",
242 				"Hostname bitbucket.org", "User bar", "Port 22",
243 				"ConnectTimeout 5", //
244 				"Host Bitbucket.org", "Hostname bitbucket.org", "User foo",
245 				"Port 29418", "ConnectTimeout 10");
246 		tmpConfig = new OpenSshConfig(tmpConfigFile.getParentFile(),
247 				tmpConfigFile);
248 		factory.setConfig(tmpConfig);
249 		Session session = createSession("ssh://bitbucket.org/something");
250 		assertEquals("bitbucket.org", session.getHost());
251 		assertEquals("bar", session.getUserName());
252 		assertEquals(22, session.getPort());
253 		assertEquals(TimeUnit.SECONDS.toMillis(5), session.getTimeout());
254 	}
255 
256 	private File createConfig(String... lines) throws Exception {
257 		File f = File.createTempFile("jsch", "test");
258 		Files.write(f.toPath(), Arrays.asList(lines));
259 		return f;
260 	}
261 
262 	private Session createSession(String uriText) throws Exception {
263 		// For this test to make sense, these few lines must correspond to the
264 		// code in JschConfigSessionFactory.getSession(). Because of
265 		// side-effects we cannot encapsulate that there properly and so we have
266 		// to duplicate this bit here. We also can't test getSession() itself
267 		// since it would try to actually connect to a server.
268 		URIish uri = new URIish(uriText);
269 		String host = uri.getHost();
270 		String user = uri.getUser();
271 		String password = uri.getPass();
272 		int port = uri.getPort();
273 		OpenSshConfig.Host hostConfig = tmpConfig.lookup(host);
274 		if (port <= 0) {
275 			port = hostConfig.getPort();
276 		}
277 		if (user == null) {
278 			user = hostConfig.getUser();
279 		}
280 		return factory.createSession(null, FS.DETECTED, user, password, host,
281 				port, hostConfig);
282 	}
283 }