KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > team > internal > ccvs > ssh2 > JSchSession


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * Atsuhiko Yamanaka, JCraft,Inc. - initial API and implementation.
10  * IBM Corporation - ongoing maintenance
11  *******************************************************************************/

12 package org.eclipse.team.internal.ccvs.ssh2;
13
14 import java.util.Enumeration JavaDoc;
15
16 import org.eclipse.core.runtime.IProgressMonitor;
17 import org.eclipse.core.runtime.OperationCanceledException;
18 import org.eclipse.jsch.core.IJSchService;
19 import org.eclipse.team.internal.ccvs.core.*;
20 import org.eclipse.team.internal.ccvs.core.connection.CVSRepositoryLocation;
21
22 import com.jcraft.jsch.*;
23
24 class JSchSession {
25     private static final int SSH_DEFAULT_PORT = 22;
26     private static JSch jsch=new JSch();
27     private static java.util.Hashtable JavaDoc pool = new java.util.Hashtable JavaDoc();
28     
29     private final Session session;
30     private final UserInfo prompter;
31     private final ICVSRepositoryLocation location;
32
33     protected static int getCVSTimeoutInMillis() {
34         //return CVSProviderPlugin.getPlugin().getTimeout() * 1000;
35
// TODO Hard-code the timeout for now since Jsch doesn't respect CVS timeout
36
// See bug 92887
37
return 60000;
38     }
39     
40     /**
41      * UserInfo wrapper class that will time how long each prompt takes
42      */

43     private static class UserInfoTimer implements UserInfo, UIKeyboardInteractive {
44
45         private UserInfo wrappedInfo;
46         private long startTime;
47         private long endTime;
48         private boolean prompting;
49         
50         public UserInfoTimer(UserInfo wrappedInfo) {
51             this.wrappedInfo = wrappedInfo;
52         }
53         
54         private synchronized void startTimer() {
55             prompting = true;
56             startTime = System.currentTimeMillis();
57         }
58         
59         private synchronized void endTimer() {
60             prompting = false;
61             endTime = System.currentTimeMillis();
62         }
63         
64         public long getLastDuration() {
65             return Math.max(0, endTime-startTime);
66         }
67         
68         public boolean hasPromptExceededTimeout() {
69             if (!isPrompting()) {
70                 return getLastDuration() > getCVSTimeoutInMillis();
71             }
72             return false;
73         }
74         
75         public String JavaDoc getPassphrase() {
76             return wrappedInfo.getPassphrase();
77         }
78
79         public String JavaDoc getPassword() {
80             return wrappedInfo.getPassword();
81         }
82
83         public boolean promptPassword(String JavaDoc arg0) {
84             try {
85                 startTimer();
86                 return wrappedInfo.promptPassword(arg0);
87             } finally {
88                 endTimer();
89             }
90         }
91
92         public boolean promptPassphrase(String JavaDoc arg0) {
93             try {
94                 startTimer();
95                 return wrappedInfo.promptPassphrase(arg0);
96             } finally {
97                 endTimer();
98             }
99         }
100
101         public boolean promptYesNo(String JavaDoc arg0) {
102             try {
103                 startTimer();
104                 return wrappedInfo.promptYesNo(arg0);
105             } finally {
106                 endTimer();
107             }
108         }
109
110         public void showMessage(String JavaDoc arg0) {
111             if(arg0.length()!=0){
112                 try {
113                     startTimer();
114                     wrappedInfo.showMessage(arg0);
115                 } finally {
116                     endTimer();
117                 }
118             }
119         }
120
121         public String JavaDoc[] promptKeyboardInteractive(String JavaDoc arg0, String JavaDoc arg1, String JavaDoc arg2, String JavaDoc[] arg3, boolean[] arg4) {
122             try {
123                 startTimer();
124                 return ((UIKeyboardInteractive)wrappedInfo).promptKeyboardInteractive(arg0, arg1, arg2, arg3, arg4);
125             } finally {
126                 endTimer();
127             }
128         }
129
130         public boolean isPrompting() {
131             return prompting;
132         }
133     }
134     
135     /**
136      * User information delegates to the IUserAuthenticator. This allows
137      * headless access to the connection method.
138      */

139     private static class MyUserInfo implements UserInfo, UIKeyboardInteractive {
140         private String JavaDoc username;
141         private String JavaDoc password;
142         private String JavaDoc passphrase;
143         private ICVSRepositoryLocation location;
144         private IUserAuthenticator authenticator;
145         private int attemptCount;
146         private boolean passwordChanged;
147         
148         MyUserInfo(String JavaDoc username, String JavaDoc password, ICVSRepositoryLocation location) {
149             this.location = location;
150             this.username = username;
151             this.password = password;
152             ICVSRepositoryLocation _location=location;
153             if(_location==null){
154                 String JavaDoc dummy=":extssh:dummy@dummy:/"; //$NON-NLS-1$
155
try{
156                     _location=CVSRepositoryLocation.fromString(dummy);
157                 }
158                 catch(CVSException e){
159                 }
160             }
161             authenticator = _location.getUserAuthenticator();
162             
163         }
164         public String JavaDoc getPassword() {
165             return password;
166         }
167         public String JavaDoc getPassphrase() {
168             return passphrase;
169         }
170         public boolean promptYesNo(String JavaDoc str) {
171             int prompt = authenticator.prompt(
172                     location,
173                     IUserAuthenticator.QUESTION,
174                     CVSSSH2Messages.JSchSession_5,
175                     str,
176                     new int[] {IUserAuthenticator.YES_ID, IUserAuthenticator.NO_ID},
177                     0 //yes the default
178
);
179             return prompt == 0;
180         }
181         private String JavaDoc promptSecret(String JavaDoc message, boolean includeLocation) throws CVSException{
182             final String JavaDoc[] _password = new String JavaDoc[1];
183             IUserInfo info = new IUserInfo() {
184                 public String JavaDoc getUsername() {
185                     return username;
186                 }
187                 public boolean isUsernameMutable() {
188                     return false;
189                 }
190                 public void setPassword(String JavaDoc password) {
191                     _password[0] = password;
192                 }
193                 public void setUsername(String JavaDoc username) {
194                 }
195             };
196             try{
197                 authenticator.promptForUserInfo(includeLocation ? location : null, info, message);
198             }
199             catch(OperationCanceledException e){
200                 _password[0]=null;
201             }
202             return _password[0];
203         }
204         public boolean promptPassphrase(String JavaDoc message) {
205             try{
206                 String JavaDoc _passphrase=promptSecret(message, false);
207                 if(_passphrase!=null){
208                   passphrase=_passphrase;
209                 }
210                 return _passphrase!=null;
211             }
212             catch(CVSException e){
213                 return false;
214             }
215         }
216         public boolean promptPassword(String JavaDoc message) {
217             try{
218                 String JavaDoc _password=promptSecret(message, true);
219                 if(_password!=null){
220                     password=_password;
221                     // Cache the password with the repository location on the memory.
222
if(location!=null)
223                         ((CVSRepositoryLocation)location).setPassword(password);
224                 }
225                 return _password!=null;
226             }
227             catch(CVSException e){
228                 return false;
229             }
230         }
231         public void showMessage(String JavaDoc message) {
232             authenticator.prompt(
233                     location,
234                     IUserAuthenticator.INFORMATION,
235                     CVSSSH2Messages.JSchSession_5,
236                     message,
237                     new int[] {IUserAuthenticator.OK_ID},
238                     IUserAuthenticator.OK_ID
239                     );
240             
241         }
242         public String JavaDoc[] promptKeyboardInteractive(String JavaDoc destination,
243                 String JavaDoc name,
244                 String JavaDoc instruction,
245                 String JavaDoc[] prompt,
246                 boolean[] echo){
247             if (prompt.length == 0) {
248                 // No need to prompt, just return an empty String array
249
return new String JavaDoc[0];
250             }
251             try{
252                 if (attemptCount == 0 && password != null && prompt.length == 1 && prompt[0].trim().equalsIgnoreCase("password:")) { //$NON-NLS-1$
253
// Return the provided password the first time but always prompt on subsequent tries
254
attemptCount++;
255                     return new String JavaDoc[] { password };
256                 }
257                 String JavaDoc[] result=
258                     authenticator.promptForKeyboradInteractive(location,
259                                                                 destination,
260                                                                 name,
261                                                                 instruction,
262                                                                 prompt,
263                                                                 echo);
264                 if (result == null)
265                     return null; // canceled
266
if (result.length == 1 && prompt.length == 1 && prompt[0].trim().equalsIgnoreCase("password:")) { //$NON-NLS-1$
267
password = result[0];
268                     passwordChanged = true;
269                 }
270                 attemptCount++;
271                 return result;
272             }
273             catch(OperationCanceledException e){
274                 return null;
275             }
276             catch(CVSException e){
277                 return null;
278             }
279         }
280         
281         /**
282          * Callback to indicate that a connection is about to be attempted
283          */

284         public void aboutToConnect() {
285             attemptCount = 0;
286             passwordChanged = false;
287         }
288         
289         /**
290          * Callback to indicate that a connection was made
291          */

292         public void connectionMade() {
293             attemptCount = 0;
294             if (passwordChanged && password != null && location != null) {
295                 // We were prompted for and returned a password so record it with the location
296
location.setPassword(password);
297             }
298         }
299     }
300
301     public static boolean isAuthenticationFailure(JSchException ee) {
302         return ee.getMessage().equals("Auth fail"); //$NON-NLS-1$
303
}
304     
305     static JSchSession getSession(ICVSRepositoryLocation location, String JavaDoc username, String JavaDoc password, String JavaDoc hostname, int port, IProgressMonitor monitor) throws JSchException {
306
307         if (port == ICVSRepositoryLocation.USE_DEFAULT_PORT)
308             port = getPort(location);
309         
310         String JavaDoc key = getPoolKey(username, hostname, port);
311
312         try {
313             JSchSession jschSession = (JSchSession) pool.get(key);
314             if (jschSession != null && !jschSession.getSession().isConnected()) {
315                 pool.remove(key);
316                 jschSession = null;
317             }
318
319             if (jschSession == null) {
320                 MyUserInfo ui = new MyUserInfo(username, password, location);
321                 UserInfoTimer wrapperUI = new UserInfoTimer(ui);
322                 ui.aboutToConnect();
323                 
324                 Session session = null;
325                 try {
326                     session = createSession(username, password, hostname, port, wrapperUI, monitor);
327                 } catch (JSchException e) {
328                     if (isAuthenticationFailure(e) && wrapperUI.hasPromptExceededTimeout()) {
329                         // Try again since the previous prompt may have obtained the proper credentials from the user
330
session = createSession(username, password, hostname, port, wrapperUI, monitor);
331                     } else {
332                         throw e;
333                     }
334                 }
335                 if (session == null)
336                     throw new JSchException("The JSch service is not available");
337                 ui.connectionMade();
338                 JSchSession schSession = new JSchSession(session, location, wrapperUI);
339                 pool.put(key, schSession);
340                 return schSession;
341             }
342             return jschSession;
343         } catch (JSchException e) {
344             pool.remove(key);
345             if(e.toString().indexOf("Auth cancel")!=-1){ //$NON-NLS-1$
346
throw new OperationCanceledException();
347             }
348             throw e;
349         }
350     }
351
352     private static Session createSession(String JavaDoc username, String JavaDoc password, String JavaDoc hostname, int port, UserInfo wrapperUI, IProgressMonitor monitor) throws JSchException {
353         IJSchService service = CVSSSH2Plugin.getDefault().getJSchService();
354         if (service == null)
355             return null;
356         Session session = service.createSession(hostname, port, username);
357         session.setTimeout(getCVSTimeoutInMillis());
358         if (password != null)
359             session.setPassword(password);
360         session.setUserInfo(wrapperUI);
361         service.connect(session, getCVSTimeoutInMillis(), monitor);
362         return session;
363     }
364
365     private static String JavaDoc getPoolKey(String JavaDoc username, String JavaDoc hostname, int port) {
366         return username + "@" + hostname + ":" + port; //$NON-NLS-1$ //$NON-NLS-2$
367
}
368
369     private static String JavaDoc getPoolKey(ICVSRepositoryLocation location){
370         return location.getUsername() + "@" + location.getHost() + ":" + getPort(location); //$NON-NLS-1$ //$NON-NLS-2$
371
}
372
373     private static int getPort(ICVSRepositoryLocation location) {
374         int port = location.getPort();
375         if (port == ICVSRepositoryLocation.USE_DEFAULT_PORT)
376             port = SSH_DEFAULT_PORT;
377         return port;
378     }
379
380     static void shutdown() {
381         if (jsch != null && pool.size() > 0) {
382             for (Enumeration JavaDoc e = pool.elements(); e.hasMoreElements(); ) {
383                 JSchSession session = (JSchSession) (e.nextElement());
384                 try {
385                     session.getSession().disconnect();
386                 } catch (Exception JavaDoc ee) {
387                 }
388             }
389             pool.clear();
390         }
391     }
392   static JSch getJSch(){
393     return jsch;
394   }
395   
396     private JSchSession(Session session, ICVSRepositoryLocation location, UserInfo prompter) {
397         this.session = session;
398         this.location = location;
399         this.prompter = prompter;
400     }
401
402     public Session getSession() {
403         return session;
404     }
405
406     public UserInfo getPrompter() {
407         return prompter;
408     }
409
410     public boolean hasPromptExceededTimeout() {
411         if (prompter instanceof UserInfoTimer) {
412             UserInfoTimer timer = (UserInfoTimer) prompter;
413             if (!timer.isPrompting()) {
414                 return timer.getLastDuration() > getCVSTimeoutInMillis();
415             }
416         }
417         return false;
418     }
419     
420     public void dispose() {
421         if (session.isConnected()) {
422             session.disconnect();
423         }
424         pool.remove(getPoolKey(location));
425     }
426
427 }
428
Popular Tags