Take care of errors reported from the server when upload command is started
[egit/zawir.git] / org.spearce.jgit / src / org / spearce / jgit / transport / DefaultSshSessionFactory.java
blob5924a041730110e3b765d27f8c523d672c61321b
1 /*
2 * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
3 * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or
8 * without modification, are permitted provided that the following
9 * conditions are met:
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * - Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
19 * - Neither the name of the Git Development Community nor the
20 * names of its contributors may be used to endorse or promote
21 * products derived from this software without specific prior
22 * written permission.
24 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
25 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
26 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
29 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
32 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
34 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
36 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 package org.spearce.jgit.transport;
41 import java.awt.Container;
42 import java.awt.GridBagConstraints;
43 import java.awt.GridBagLayout;
44 import java.awt.Insets;
45 import java.io.File;
46 import java.io.FileInputStream;
47 import java.io.FileNotFoundException;
48 import java.io.IOException;
49 import java.io.OutputStream;
50 import java.security.AccessController;
51 import java.security.PrivilegedAction;
53 import javax.swing.JLabel;
54 import javax.swing.JOptionPane;
55 import javax.swing.JPanel;
56 import javax.swing.JPasswordField;
57 import javax.swing.JTextField;
59 import org.spearce.jgit.util.FS;
61 import com.jcraft.jsch.JSch;
62 import com.jcraft.jsch.JSchException;
63 import com.jcraft.jsch.Session;
64 import com.jcraft.jsch.UIKeyboardInteractive;
65 import com.jcraft.jsch.UserInfo;
67 /**
68 * Loads known hosts and private keys from <code>$HOME/.ssh</code>.
69 * <p>
70 * This is the default implementation used by JGit and provides most of the
71 * compatibility necessary to match OpenSSH, a popular implementation of SSH
72 * used by C Git.
73 * <p>
74 * If user interactivity is required by SSH (e.g. to obtain a password) AWT is
75 * used to display a password input field to the end-user.
77 class DefaultSshSessionFactory extends SshSessionFactory {
78 /** IANA assigned port number for SSH. */
79 private static final int SSH_PORT = 22;
81 private JSch userJSch;
83 @Override
84 public synchronized Session getSession(String user, String pass,
85 String host, int port) throws JSchException {
86 if (port <= 0)
87 port = SSH_PORT;
88 if (user == null)
89 user = userName();
91 final Session session = getUserJSch().getSession(user, host, port);
92 if (pass != null)
93 session.setPassword(pass);
94 else
95 session.setUserInfo(new AWT_UserInfo());
96 return session;
99 private static String userName() {
100 return AccessController.doPrivileged(new PrivilegedAction<String>() {
101 public String run() {
102 return System.getProperty("user.name");
107 private JSch getUserJSch() throws JSchException {
108 if (userJSch == null) {
109 final JSch sch = new JSch();
110 knownHosts(sch);
111 identities(sch);
112 userJSch = sch;
114 return userJSch;
117 private void knownHosts(final JSch sch) throws JSchException {
118 final File home = FS.userHome();
119 if (home == null)
120 return;
121 final File known_hosts = new File(new File(home, ".ssh"), "known_hosts");
122 try {
123 final FileInputStream in = new FileInputStream(known_hosts);
124 try {
125 sch.setKnownHosts(in);
126 } finally {
127 in.close();
129 } catch (FileNotFoundException none) {
130 // Oh well. They don't have a known hosts in home.
131 } catch (IOException err) {
132 // Oh well. They don't have a known hosts in home.
136 private void identities(final JSch sch) throws JSchException {
137 final File home = FS.userHome();
138 if (home == null)
139 return;
140 final File sshdir = new File(home, ".ssh");
141 final File[] keys = sshdir.listFiles();
142 if (keys == null)
143 return;
144 for (int i = 0; i < keys.length; i++) {
145 final File pk = keys[i];
146 final String n = pk.getName();
147 if (!n.endsWith(".pub"))
148 continue;
149 final File k = new File(sshdir, n.substring(0, n.length() - 4));
150 if (!k.isFile())
151 continue;
152 sch.addIdentity(k.getAbsolutePath());
156 private static class AWT_UserInfo implements UserInfo,
157 UIKeyboardInteractive {
158 private String passwd;
160 private String passphrase;
162 public void showMessage(final String msg) {
163 JOptionPane.showMessageDialog(null, msg);
166 public boolean promptYesNo(final String msg) {
167 return JOptionPane.showConfirmDialog(null, msg, "Warning",
168 JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
171 public boolean promptPassword(final String msg) {
172 passwd = null;
173 final JPasswordField passwordField = new JPasswordField(20);
174 final int result = JOptionPane.showConfirmDialog(null,
175 new Object[] { passwordField }, msg,
176 JOptionPane.OK_CANCEL_OPTION);
177 if (result == JOptionPane.OK_OPTION) {
178 passwd = new String(passwordField.getPassword());
179 return true;
181 return false;
184 public boolean promptPassphrase(final String msg) {
185 passphrase = null;
186 final JPasswordField passwordField = new JPasswordField(20);
187 final int result = JOptionPane.showConfirmDialog(null,
188 new Object[] { passwordField }, msg,
189 JOptionPane.OK_CANCEL_OPTION);
190 if (result == JOptionPane.OK_OPTION) {
191 passphrase = new String(passwordField.getPassword());
192 return true;
194 return false;
197 public String getPassword() {
198 return passwd;
201 public String getPassphrase() {
202 return passphrase;
205 public String[] promptKeyboardInteractive(final String destination,
206 final String name, final String instruction,
207 final String[] prompt, final boolean[] echo) {
208 final GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1,
209 1, 1, GridBagConstraints.NORTHWEST,
210 GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0);
211 final Container panel = new JPanel();
212 panel.setLayout(new GridBagLayout());
214 gbc.weightx = 1.0;
215 gbc.gridwidth = GridBagConstraints.REMAINDER;
216 gbc.gridx = 0;
217 panel.add(new JLabel(instruction), gbc);
218 gbc.gridy++;
220 gbc.gridwidth = GridBagConstraints.RELATIVE;
222 final JTextField[] texts = new JTextField[prompt.length];
223 for (int i = 0; i < prompt.length; i++) {
224 gbc.fill = GridBagConstraints.NONE;
225 gbc.gridx = 0;
226 gbc.weightx = 1;
227 panel.add(new JLabel(prompt[i]), gbc);
229 gbc.gridx = 1;
230 gbc.fill = GridBagConstraints.HORIZONTAL;
231 gbc.weighty = 1;
232 if (echo[i]) {
233 texts[i] = new JTextField(20);
234 } else {
235 texts[i] = new JPasswordField(20);
237 panel.add(texts[i], gbc);
238 gbc.gridy++;
241 if (JOptionPane.showConfirmDialog(null, panel, destination + ": "
242 + name, JOptionPane.OK_CANCEL_OPTION,
243 JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) {
244 String[] response = new String[prompt.length];
245 for (int i = 0; i < prompt.length; i++) {
246 response[i] = texts[i].getText();
248 return response;
250 return null; // cancel
254 @Override
255 public OutputStream getErrorStream() {
256 return System.err;