~ubuntu-branches/ubuntu/oneiric/monodevelop/oneiric

« back to all changes in this revision

Viewing changes to contrib/NGit/NGit.Transport/JschConfigSessionFactory.cs

  • Committer: Bazaar Package Importer
  • Author(s): Jo Shields
  • Date: 2011-06-27 17:03:13 UTC
  • mto: (1.8.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 54.
  • Revision ID: james.westby@ubuntu.com-20110627170313-6cvz3s19x6e9hqe9
ImportĀ upstreamĀ versionĀ 2.5.92+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
This code is derived from jgit (http://eclipse.org/jgit).
 
3
Copyright owners are documented in jgit'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
 
 
44
using System;
 
45
using System.Collections.Generic;
 
46
using System.IO;
 
47
using NGit;
 
48
using NGit.Errors;
 
49
using NGit.Transport;
 
50
using NGit.Util;
 
51
using NSch;
 
52
using Sharpen;
 
53
 
 
54
namespace NGit.Transport
 
55
{
 
56
        /// <summary>
 
57
        /// The base session factory that loads known hosts and private keys from
 
58
        /// <code>$HOME/.ssh</code>.
 
59
        /// </summary>
 
60
        /// <remarks>
 
61
        /// The base session factory that loads known hosts and private keys from
 
62
        /// <code>$HOME/.ssh</code>.
 
63
        /// <p>
 
64
        /// This is the default implementation used by JGit and provides most of the
 
65
        /// compatibility necessary to match OpenSSH, a popular implementation of SSH
 
66
        /// used by C Git.
 
67
        /// <p>
 
68
        /// The factory does not provide UI behavior. Override the method
 
69
        /// <see cref="Configure(Host, NSch.Session)">Configure(Host, NSch.Session)</see>
 
70
        /// to supply appropriate
 
71
        /// <see cref="NSch.UserInfo">NSch.UserInfo</see>
 
72
        /// to the session.
 
73
        /// </remarks>
 
74
        public abstract class JschConfigSessionFactory : SshSessionFactory
 
75
        {
 
76
                private readonly IDictionary<string, JSch> byIdentityFile = new Dictionary<string
 
77
                        , JSch>();
 
78
 
 
79
                private JSch defaultJSch;
 
80
 
 
81
                private OpenSshConfig config;
 
82
 
 
83
                /// <exception cref="NGit.Errors.TransportException"></exception>
 
84
                public override RemoteSession GetSession(URIish uri, CredentialsProvider credentialsProvider
 
85
                        , FS fs, int tms)
 
86
                {
 
87
                        lock (this)
 
88
                        {
 
89
                                string user = uri.GetUser();
 
90
                                string pass = uri.GetPass();
 
91
                                string host = uri.GetHost();
 
92
                                int port = uri.GetPort();
 
93
                                try
 
94
                                {
 
95
                                        if (config == null)
 
96
                                        {
 
97
                                                config = OpenSshConfig.Get(fs);
 
98
                                        }
 
99
                                        OpenSshConfig.Host hc = config.Lookup(host);
 
100
                                        host = hc.GetHostName();
 
101
                                        if (port <= 0)
 
102
                                        {
 
103
                                                port = hc.GetPort();
 
104
                                        }
 
105
                                        if (user == null)
 
106
                                        {
 
107
                                                user = hc.GetUser();
 
108
                                        }
 
109
                                        Session session = CreateSession(hc, user, host, port, fs);
 
110
                                        if (pass != null)
 
111
                                        {
 
112
                                                session.SetPassword(pass);
 
113
                                        }
 
114
                                        string strictHostKeyCheckingPolicy = hc.GetStrictHostKeyChecking();
 
115
                                        if (strictHostKeyCheckingPolicy != null)
 
116
                                        {
 
117
                                                session.SetConfig("StrictHostKeyChecking", strictHostKeyCheckingPolicy);
 
118
                                        }
 
119
                                        string pauth = hc.GetPreferredAuthentications();
 
120
                                        if (pauth != null)
 
121
                                        {
 
122
                                                session.SetConfig("PreferredAuthentications", pauth);
 
123
                                        }
 
124
                                        if (credentialsProvider != null && (!hc.IsBatchMode() || !credentialsProvider.IsInteractive
 
125
                                                ()))
 
126
                                        {
 
127
                                                session.SetUserInfo(new CredentialsProviderUserInfo(session, credentialsProvider)
 
128
                                                        );
 
129
                                        }
 
130
                                        Configure(hc, session);
 
131
                                        if (!session.IsConnected())
 
132
                                        {
 
133
                                                session.Connect(tms);
 
134
                                        }
 
135
                                        return new JschSession(session, uri);
 
136
                                }
 
137
                                catch (JSchException je)
 
138
                                {
 
139
                                        Exception c = je.InnerException;
 
140
                                        if (c is UnknownHostException)
 
141
                                        {
 
142
                                                throw new TransportException(uri, JGitText.Get().unknownHost);
 
143
                                        }
 
144
                                        if (c is ConnectException)
 
145
                                        {
 
146
                                                throw new TransportException(uri, c.Message);
 
147
                                        }
 
148
                                        throw new TransportException(uri, je.Message, je);
 
149
                                }
 
150
                        }
 
151
                }
 
152
 
 
153
                /// <summary>Create a new remote session for the requested address.</summary>
 
154
                /// <remarks>Create a new remote session for the requested address.</remarks>
 
155
                /// <param name="hc">host configuration</param>
 
156
                /// <param name="user">login to authenticate as.</param>
 
157
                /// <param name="host">server name to connect to.</param>
 
158
                /// <param name="port">port number of the SSH daemon (typically 22).</param>
 
159
                /// <param name="fs">
 
160
                /// the file system abstraction which will be necessary to
 
161
                /// perform certain file system operations.
 
162
                /// </param>
 
163
                /// <returns>new session instance, but otherwise unconfigured.</returns>
 
164
                /// <exception cref="NSch.JSchException">the session could not be created.</exception>
 
165
                protected internal virtual Session CreateSession(OpenSshConfig.Host hc, string user
 
166
                        , string host, int port, FS fs)
 
167
                {
 
168
                        return GetJSch(hc, fs).GetSession(user, host, port);
 
169
                }
 
170
 
 
171
                /// <summary>
 
172
                /// Provide additional configuration for the session based on the host
 
173
                /// information.
 
174
                /// </summary>
 
175
                /// <remarks>
 
176
                /// Provide additional configuration for the session based on the host
 
177
                /// information. This method could be used to supply
 
178
                /// <see cref="NSch.UserInfo">NSch.UserInfo</see>
 
179
                /// .
 
180
                /// </remarks>
 
181
                /// <param name="hc">host configuration</param>
 
182
                /// <param name="session">session to configure</param>
 
183
                protected internal abstract void Configure(OpenSshConfig.Host hc, Session session
 
184
                        );
 
185
 
 
186
                /// <summary>Obtain the JSch used to create new sessions.</summary>
 
187
                /// <remarks>Obtain the JSch used to create new sessions.</remarks>
 
188
                /// <param name="hc">host configuration</param>
 
189
                /// <param name="fs">
 
190
                /// the file system abstraction which will be necessary to
 
191
                /// perform certain file system operations.
 
192
                /// </param>
 
193
                /// <returns>the JSch instance to use.</returns>
 
194
                /// <exception cref="NSch.JSchException">the user configuration could not be created.
 
195
                ///     </exception>
 
196
                protected internal virtual JSch GetJSch(OpenSshConfig.Host hc, FS fs)
 
197
                {
 
198
                        if (defaultJSch == null)
 
199
                        {
 
200
                                defaultJSch = CreateDefaultJSch(fs);
 
201
                                foreach (object name in defaultJSch.GetIdentityNames())
 
202
                                {
 
203
                                        byIdentityFile.Put((string)name, defaultJSch);
 
204
                                }
 
205
                        }
 
206
                        FilePath identityFile = hc.GetIdentityFile();
 
207
                        if (identityFile == null)
 
208
                        {
 
209
                                return defaultJSch;
 
210
                        }
 
211
                        string identityKey = identityFile.GetAbsolutePath();
 
212
                        JSch jsch = byIdentityFile.Get(identityKey);
 
213
                        if (jsch == null)
 
214
                        {
 
215
                                jsch = new JSch();
 
216
                                jsch.SetHostKeyRepository(defaultJSch.GetHostKeyRepository());
 
217
                                jsch.AddIdentity(identityKey);
 
218
                                byIdentityFile.Put(identityKey, jsch);
 
219
                        }
 
220
                        return jsch;
 
221
                }
 
222
 
 
223
                /// <param name="fs">
 
224
                /// the file system abstraction which will be necessary to
 
225
                /// perform certain file system operations.
 
226
                /// </param>
 
227
                /// <returns>the new default JSch implementation.</returns>
 
228
                /// <exception cref="NSch.JSchException">known host keys cannot be loaded.</exception>
 
229
                protected internal virtual JSch CreateDefaultJSch(FS fs)
 
230
                {
 
231
                        JSch jsch = new JSch();
 
232
                        KnownHosts(jsch, fs);
 
233
                        Identities(jsch, fs);
 
234
                        return jsch;
 
235
                }
 
236
 
 
237
                /// <exception cref="NSch.JSchException"></exception>
 
238
                private static void KnownHosts(JSch sch, FS fs)
 
239
                {
 
240
                        FilePath home = fs.UserHome();
 
241
                        if (home == null)
 
242
                        {
 
243
                                return;
 
244
                        }
 
245
                        FilePath known_hosts = new FilePath(new FilePath(home, ".ssh"), "known_hosts");
 
246
                        try
 
247
                        {
 
248
                                FileInputStream @in = new FileInputStream(known_hosts);
 
249
                                try
 
250
                                {
 
251
                                        sch.SetKnownHosts(@in);
 
252
                                }
 
253
                                finally
 
254
                                {
 
255
                                        @in.Close();
 
256
                                }
 
257
                        }
 
258
                        catch (FileNotFoundException)
 
259
                        {
 
260
                        }
 
261
                        catch (IOException)
 
262
                        {
 
263
                        }
 
264
                }
 
265
 
 
266
                // Oh well. They don't have a known hosts in home.
 
267
                // Oh well. They don't have a known hosts in home.
 
268
                private static void Identities(JSch sch, FS fs)
 
269
                {
 
270
                        FilePath home = fs.UserHome();
 
271
                        if (home == null)
 
272
                        {
 
273
                                return;
 
274
                        }
 
275
                        FilePath sshdir = new FilePath(home, ".ssh");
 
276
                        if (sshdir.IsDirectory())
 
277
                        {
 
278
                                LoadIdentity(sch, new FilePath(sshdir, "identity"));
 
279
                                LoadIdentity(sch, new FilePath(sshdir, "id_rsa"));
 
280
                                LoadIdentity(sch, new FilePath(sshdir, "id_dsa"));
 
281
                        }
 
282
                }
 
283
 
 
284
                private static void LoadIdentity(JSch sch, FilePath priv)
 
285
                {
 
286
                        if (priv.IsFile())
 
287
                        {
 
288
                                try
 
289
                                {
 
290
                                        sch.AddIdentity(priv.GetAbsolutePath());
 
291
                                }
 
292
                                catch (JSchException)
 
293
                                {
 
294
                                }
 
295
                        }
 
296
                }
 
297
                // Instead, pretend the key doesn't exist.
 
298
        }
 
299
}