2 * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
3 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
4 * Copyright (C) 2009, JetBrains s.r.o.
5 * Copyright (C) 2009, Google, Inc.
9 * Redistribution and use in source and binary forms, with or
10 * without modification, are permitted provided that the following
13 * - Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
16 * - Redistributions in binary form must reproduce the above
17 * copyright notice, this list of conditions and the following
18 * disclaimer in the documentation and/or other materials provided
19 * with the distribution.
21 * - Neither the name of the Git Development Community nor the
22 * names of its contributors may be used to endorse or promote
23 * products derived from this software without specific prior
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
27 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
28 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
31 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
33 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
35 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
38 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 package org
.spearce
.jgit
.transport
;
43 import java
.io
.FileInputStream
;
44 import java
.io
.FileNotFoundException
;
45 import java
.io
.IOException
;
46 import java
.io
.OutputStream
;
47 import java
.util
.HashMap
;
50 import org
.spearce
.jgit
.util
.FS
;
52 import com
.jcraft
.jsch
.JSch
;
53 import com
.jcraft
.jsch
.JSchException
;
54 import com
.jcraft
.jsch
.Session
;
55 import com
.jcraft
.jsch
.UserInfo
;
58 * The base session factory that loads known hosts and private keys from
59 * <code>$HOME/.ssh</code>.
61 * This is the default implementation used by JGit and provides most of the
62 * compatibility necessary to match OpenSSH, a popular implementation of SSH
65 * The factory does not provide UI behavior. Override the method
66 * {@link #configure(org.spearce.jgit.transport.OpenSshConfig.Host, Session)}
67 * to supply appropriate {@link UserInfo} to the session.
69 public abstract class SshConfigSessionFactory
extends SshSessionFactory
{
70 private final Map
<String
, JSch
> byIdentityFile
= new HashMap
<String
, JSch
>();
72 private JSch defaultJSch
;
74 private OpenSshConfig config
;
77 public synchronized Session
getSession(String user
, String pass
,
78 String host
, int port
) throws JSchException
{
79 final OpenSshConfig
.Host hc
= getConfig().lookup(host
);
80 host
= hc
.getHostName();
86 final Session session
= createSession(hc
, user
, host
, port
);
88 session
.setPassword(pass
);
89 final String strictHostKeyCheckingPolicy
= hc
90 .getStrictHostKeyChecking();
91 if (strictHostKeyCheckingPolicy
!= null)
92 session
.setConfig("StrictHostKeyChecking",
93 strictHostKeyCheckingPolicy
);
94 final String pauth
= hc
.getPreferredAuthentications();
96 session
.setConfig("PreferredAuthentications", pauth
);
97 configure(hc
, session
);
102 * Create a new JSch session for the requested address.
107 * login to authenticate as.
109 * server name to connect to.
111 * port number of the SSH daemon (typically 22).
112 * @return new session instance, but otherwise unconfigured.
113 * @throws JSchException
114 * the session could not be created.
116 protected Session
createSession(final OpenSshConfig
.Host hc
,
117 final String user
, final String host
, final int port
)
118 throws JSchException
{
119 return getJSch(hc
).getSession(user
, host
, port
);
123 * Provide additional configuration for the session based on the host
124 * information. This method could be used to supply {@link UserInfo}.
129 * session to configure
131 protected abstract void configure(OpenSshConfig
.Host hc
, Session session
);
134 * Obtain the JSch used to create new sessions.
138 * @return the JSch instance to use.
139 * @throws JSchException
140 * the user configuration could not be created.
142 protected JSch
getJSch(final OpenSshConfig
.Host hc
) throws JSchException
{
143 final JSch def
= getDefaultJSch();
144 final File identityFile
= hc
.getIdentityFile();
145 if (identityFile
== null) {
149 final String identityKey
= identityFile
.getAbsolutePath();
150 JSch jsch
= byIdentityFile
.get(identityKey
);
153 jsch
.setHostKeyRepository(def
.getHostKeyRepository());
154 jsch
.addIdentity(identityKey
);
155 byIdentityFile
.put(identityKey
, jsch
);
160 private JSch
getDefaultJSch() throws JSchException
{
161 if (defaultJSch
== null) {
162 defaultJSch
= createDefaultJSch();
163 for (Object name
: defaultJSch
.getIdentityNames()) {
164 byIdentityFile
.put((String
) name
, defaultJSch
);
171 * @return the new default JSch implementation.
172 * @throws JSchException
173 * known host keys cannot be loaded.
175 protected JSch
createDefaultJSch() throws JSchException
{
176 final JSch jsch
= new JSch();
182 private OpenSshConfig
getConfig() {
184 config
= OpenSshConfig
.get();
188 private static void knownHosts(final JSch sch
) throws JSchException
{
189 final File home
= FS
.userHome();
192 final File known_hosts
= new File(new File(home
, ".ssh"), "known_hosts");
194 final FileInputStream in
= new FileInputStream(known_hosts
);
196 sch
.setKnownHosts(in
);
200 } catch (FileNotFoundException none
) {
201 // Oh well. They don't have a known hosts in home.
202 } catch (IOException err
) {
203 // Oh well. They don't have a known hosts in home.
207 private static void identities(final JSch sch
) {
208 final File home
= FS
.userHome();
211 final File sshdir
= new File(home
, ".ssh");
212 if (sshdir
.isDirectory()) {
213 loadIdentity(sch
, new File(sshdir
, "identity"));
214 loadIdentity(sch
, new File(sshdir
, "id_rsa"));
215 loadIdentity(sch
, new File(sshdir
, "id_dsa"));
219 private static void loadIdentity(final JSch sch
, final File priv
) {
222 sch
.addIdentity(priv
.getAbsolutePath());
223 } catch (JSchException e
) {
224 // Instead, pretend the key doesn't exist.
230 public OutputStream
getErrorStream() {
231 return new OutputStream() {
232 private StringBuilder all
= new StringBuilder();
234 private StringBuilder sb
= new StringBuilder();
236 public String
toString() {
237 String r
= all
.toString();
238 while (r
.endsWith("\n"))
239 r
= r
.substring(0, r
.length() - 1);
244 public void write(final int b
) throws IOException
{
246 System
.err
.print('\r');
253 final String line
= sb
.toString();
254 System
.err
.print(line
);
256 sb
= new StringBuilder();