1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49 package org.eclipse.jgit.transport;
50
51 import java.io.File;
52 import java.io.FileInputStream;
53 import java.io.FileNotFoundException;
54 import java.io.IOException;
55 import java.net.ConnectException;
56 import java.net.UnknownHostException;
57 import java.util.HashMap;
58 import java.util.Map;
59
60 import org.eclipse.jgit.errors.TransportException;
61 import org.eclipse.jgit.internal.JGitText;
62 import org.eclipse.jgit.util.FS;
63
64 import com.jcraft.jsch.JSch;
65 import com.jcraft.jsch.JSchException;
66 import com.jcraft.jsch.Session;
67 import com.jcraft.jsch.UserInfo;
68
69
70
71
72
73
74
75
76
77
78
79
80
81 public abstract class JschConfigSessionFactory extends SshSessionFactory {
82 private final Map<String, JSch> byIdentityFile = new HashMap<String, JSch>();
83
84 private JSch defaultJSch;
85
86 private OpenSshConfig config;
87
88 @Override
89 public synchronized RemoteSession getSession(URIish uri,
90 CredentialsProvider credentialsProvider, FS fs, int tms)
91 throws TransportException {
92
93 String user = uri.getUser();
94 final String pass = uri.getPass();
95 String host = uri.getHost();
96 int port = uri.getPort();
97
98 try {
99 if (config == null)
100 config = OpenSshConfig.get(fs);
101
102 final OpenSshConfig.Host hc = config.lookup(host);
103 host = hc.getHostName();
104 if (port <= 0)
105 port = hc.getPort();
106 if (user == null)
107 user = hc.getUser();
108
109 Session session = createSession(credentialsProvider, fs, user,
110 pass, host, port, hc);
111
112 int retries = 0;
113 while (!session.isConnected()) {
114 try {
115 retries++;
116 session.connect(tms);
117 } catch (JSchException e) {
118 session.disconnect();
119 session = null;
120
121 knownHosts(getJSch(hc, fs), fs);
122
123 if (isAuthenticationCanceled(e)) {
124 throw e;
125 } else if (isAuthenticationFailed(e)
126 && credentialsProvider != null) {
127
128
129 if (retries < 3) {
130 credentialsProvider.reset(uri);
131 session = createSession(credentialsProvider, fs,
132 user, pass, host, port, hc);
133 } else
134 throw e;
135 } else if (retries >= hc.getConnectionAttempts()) {
136 throw e;
137 } else {
138 try {
139 Thread.sleep(1000);
140 session = createSession(credentialsProvider, fs,
141 user, pass, host, port, hc);
142 } catch (InterruptedException e1) {
143 throw new TransportException(
144 JGitText.get().transportSSHRetryInterrupt,
145 e1);
146 }
147 }
148 }
149 }
150
151 return new JschSession(session, uri);
152
153 } catch (JSchException je) {
154 final Throwable c = je.getCause();
155 if (c instanceof UnknownHostException)
156 throw new TransportException(uri, JGitText.get().unknownHost);
157 if (c instanceof ConnectException)
158 throw new TransportException(uri, c.getMessage());
159 throw new TransportException(uri, je.getMessage(), je);
160 }
161
162 }
163
164 private static boolean isAuthenticationFailed(JSchException e) {
165 return e.getCause() == null && e.getMessage().equals("Auth fail");
166 }
167
168 private static boolean isAuthenticationCanceled(JSchException e) {
169 return e.getCause() == null && e.getMessage().equals("Auth cancel");
170 }
171
172 private Session createSession(CredentialsProvider credentialsProvider,
173 FS fs, String user, final String pass, String host, int port,
174 final OpenSshConfig.Host hc) throws JSchException {
175 final Session session = createSession(hc, user, host, port, fs);
176
177
178 session.setConfig("MaxAuthTries", "1");
179 if (pass != null)
180 session.setPassword(pass);
181 final String strictHostKeyCheckingPolicy = hc
182 .getStrictHostKeyChecking();
183 if (strictHostKeyCheckingPolicy != null)
184 session.setConfig("StrictHostKeyChecking",
185 strictHostKeyCheckingPolicy);
186 final String pauth = hc.getPreferredAuthentications();
187 if (pauth != null)
188 session.setConfig("PreferredAuthentications", pauth);
189 if (credentialsProvider != null
190 && (!hc.isBatchMode() || !credentialsProvider.isInteractive())) {
191 session.setUserInfo(new CredentialsProviderUserInfo(session,
192 credentialsProvider));
193 }
194 configure(hc, session);
195 return session;
196 }
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216 protected Session createSession(final OpenSshConfig.Host hc,
217 final String user, final String host, final int port, FS fs)
218 throws JSchException {
219 return getJSch(hc, fs).getSession(user, host, port);
220 }
221
222
223
224
225
226
227
228
229
230
231 protected abstract void configure(OpenSshConfig.Host hc, Session session);
232
233
234
235
236
237
238
239
240
241
242
243
244
245 protected JSch getJSch(final OpenSshConfig.Host hc, FS fs) throws JSchException {
246 if (defaultJSch == null) {
247 defaultJSch = createDefaultJSch(fs);
248 for (Object name : defaultJSch.getIdentityNames())
249 byIdentityFile.put((String) name, defaultJSch);
250 }
251
252 final File identityFile = hc.getIdentityFile();
253 if (identityFile == null)
254 return defaultJSch;
255
256 final String identityKey = identityFile.getAbsolutePath();
257 JSch jsch = byIdentityFile.get(identityKey);
258 if (jsch == null) {
259 jsch = new JSch();
260 jsch.setHostKeyRepository(defaultJSch.getHostKeyRepository());
261 jsch.addIdentity(identityKey);
262 byIdentityFile.put(identityKey, jsch);
263 }
264 return jsch;
265 }
266
267
268
269
270
271
272
273
274
275 protected JSch createDefaultJSch(FS fs) throws JSchException {
276 final JSch jsch = new JSch();
277 knownHosts(jsch, fs);
278 identities(jsch, fs);
279 return jsch;
280 }
281
282 private static void knownHosts(final JSch sch, FS fs) throws JSchException {
283 final File home = fs.userHome();
284 if (home == null)
285 return;
286 final File known_hosts = new File(new File(home, ".ssh"), "known_hosts");
287 try {
288 final FileInputStream in = new FileInputStream(known_hosts);
289 try {
290 sch.setKnownHosts(in);
291 } finally {
292 in.close();
293 }
294 } catch (FileNotFoundException none) {
295
296 } catch (IOException err) {
297
298 }
299 }
300
301 private static void identities(final JSch sch, FS fs) {
302 final File home = fs.userHome();
303 if (home == null)
304 return;
305 final File sshdir = new File(home, ".ssh");
306 if (sshdir.isDirectory()) {
307 loadIdentity(sch, new File(sshdir, "identity"));
308 loadIdentity(sch, new File(sshdir, "id_rsa"));
309 loadIdentity(sch, new File(sshdir, "id_dsa"));
310 }
311 }
312
313 private static void loadIdentity(final JSch sch, final File priv) {
314 if (priv.isFile()) {
315 try {
316 sch.addIdentity(priv.getAbsolutePath());
317 } catch (JSchException e) {
318
319 }
320 }
321 }
322 }