source: josm/trunk/src/org/openstreetmap/josm/gui/io/CredentialDialog.java@ 4690

Last change on this file since 4690 was 4690, checked in by stoecker, 12 years ago

see #7086 - fix passing auth information to wrong server

  • Property svn:eol-style set to native
File size: 14.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.BorderLayout;
7import java.awt.Dimension;
8import java.awt.FlowLayout;
9import java.awt.Font;
10import java.awt.GridBagConstraints;
11import java.awt.GridBagLayout;
12import java.awt.Insets;
13import java.awt.event.ActionEvent;
14import java.awt.event.FocusAdapter;
15import java.awt.event.FocusEvent;
16import java.awt.event.KeyEvent;
17import java.awt.event.KeyListener;
18import java.awt.event.WindowAdapter;
19import java.awt.event.WindowEvent;
20
21import javax.swing.AbstractAction;
22import javax.swing.BorderFactory;
23import javax.swing.JCheckBox;
24import javax.swing.JComponent;
25import javax.swing.JDialog;
26import javax.swing.JLabel;
27import javax.swing.JPanel;
28import javax.swing.JPasswordField;
29import javax.swing.JTextField;
30import javax.swing.KeyStroke;
31
32import org.openstreetmap.josm.Main;
33import org.openstreetmap.josm.gui.JMultilineLabel;
34import org.openstreetmap.josm.gui.SideButton;
35import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
36import org.openstreetmap.josm.gui.help.HelpUtil;
37import org.openstreetmap.josm.gui.preferences.server.ProxyPreferencesPanel;
38import org.openstreetmap.josm.io.OsmApi;
39import org.openstreetmap.josm.tools.ImageProvider;
40import org.openstreetmap.josm.tools.WindowGeometry;
41
42public class CredentialDialog extends JDialog {
43
44 static public CredentialDialog getOsmApiCredentialDialog(String username, String password, String host, String saveUsernameAndPasswordCheckboxText) {
45 CredentialDialog dialog = new CredentialDialog(saveUsernameAndPasswordCheckboxText);
46 if(OsmApi.getOsmApi().getHost().equals(host)) {
47 dialog.prepareForOsmApiCredentials(username, password);
48 } else {
49 dialog.prepareForOtherHostCredentials(username, password, host);
50 }
51 dialog.pack();
52 return dialog;
53 }
54
55 static public CredentialDialog getHttpProxyCredentialDialog(String username, String password, String host, String saveUsernameAndPasswordCheckboxText) {
56 CredentialDialog dialog = new CredentialDialog(saveUsernameAndPasswordCheckboxText);
57 dialog.prepareForProxyCredentials(username, password);
58 dialog.pack();
59 return dialog;
60 }
61
62 private boolean canceled;
63 protected CredentialPanel pnlCredentials;
64 String saveUsernameAndPasswordCheckboxText;
65
66 public boolean isCanceled() {
67 return canceled;
68 }
69
70 protected void setCanceled(boolean canceled) {
71 this.canceled = canceled;
72 }
73
74 @Override
75 public void setVisible(boolean visible) {
76 if (visible) {
77 WindowGeometry.centerInWindow(Main.parent, new Dimension(350,300)).apply(this);
78 }
79 super.setVisible(visible);
80 }
81
82 protected JPanel createButtonPanel() {
83 JPanel pnl = new JPanel(new FlowLayout());
84 pnl.add(new SideButton(new OKAction()));
85 pnl.add(new SideButton(new CancelAction()));
86 pnl.add(new SideButton(new ContextSensitiveHelpAction(HelpUtil.ht("/Dialog/Password"))));
87 return pnl;
88 }
89
90 protected void build() {
91 getContentPane().setLayout(new BorderLayout());
92 getContentPane().add(createButtonPanel(), BorderLayout.SOUTH);
93
94 addWindowListener(new WindowEventHander());
95 getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), "escape");
96 getRootPane().getActionMap().put("escape", new CancelAction());
97
98 getRootPane().setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
99 }
100
101 public CredentialDialog(String saveUsernameAndPasswordCheckboxText) {
102 this.saveUsernameAndPasswordCheckboxText = saveUsernameAndPasswordCheckboxText;
103 setModalityType(ModalityType.DOCUMENT_MODAL);
104 try {
105 setAlwaysOnTop(true);
106 } catch(SecurityException e) {
107 System.out.println(tr("Warning: failed to put Credential Dialog always on top. Caught security exception."));
108 }
109 build();
110 }
111
112 public void prepareForOsmApiCredentials(String username, String password) {
113 setTitle(tr("Enter credentials for OSM API"));
114 getContentPane().add(pnlCredentials = new OsmApiCredentialsPanel(this), BorderLayout.CENTER);
115 pnlCredentials.init(username, password);
116 validate();
117 }
118
119 public void prepareForOtherHostCredentials(String username, String password, String host) {
120 setTitle(tr("Enter credentials for host"));
121 getContentPane().add(pnlCredentials = new OtherHostCredentialsPanel(this, host), BorderLayout.CENTER);
122 pnlCredentials.init(username, password);
123 validate();
124 }
125
126 public void prepareForProxyCredentials(String username, String password) {
127 setTitle(tr("Enter credentials for HTTP proxy"));
128 getContentPane().add(pnlCredentials = new HttpProxyCredentialsPanel(this), BorderLayout.CENTER);
129 pnlCredentials.init(username, password);
130 validate();
131 }
132
133 public String getUsername() {
134 if (pnlCredentials== null) return null;
135 return pnlCredentials.getUserName();
136 }
137
138 public char[] getPassword() {
139 if (pnlCredentials== null) return null;
140 return pnlCredentials.getPassword();
141 }
142
143 public boolean isSaveCredentials() {
144 if (pnlCredentials== null) return false;
145 return pnlCredentials.isSaveCredentials();
146 }
147
148 protected static class CredentialPanel extends JPanel {
149 protected JTextField tfUserName;
150 protected JPasswordField tfPassword;
151 protected JCheckBox cbSaveCredentials;
152 protected JMultilineLabel lblHeading;
153 protected JMultilineLabel lblWarning;
154 protected CredentialDialog owner; // owner Dependency Injection to use Key listeners for username and password text fields
155
156 protected void build() {
157 tfUserName = new JTextField(20);
158 tfPassword = new JPasswordField(20);
159 tfUserName.addFocusListener(new SelectAllOnFocusHandler());
160 tfPassword.addFocusListener(new SelectAllOnFocusHandler());
161 tfUserName.addKeyListener(new TFKeyListener(owner, tfUserName, tfPassword));
162 tfPassword.addKeyListener(new TFKeyListener(owner, tfPassword, tfUserName));
163 cbSaveCredentials = new JCheckBox(owner.saveUsernameAndPasswordCheckboxText);
164
165 setLayout(new GridBagLayout());
166 GridBagConstraints gc = new GridBagConstraints();
167 gc.gridwidth = 2;
168 gc.gridheight = 1;
169 gc.fill = GridBagConstraints.HORIZONTAL;
170 gc.weightx = 1.0;
171 gc.weighty = 0.0;
172 gc.insets = new Insets(0,0,10,0);
173 add(lblHeading = new JMultilineLabel(""), gc);
174
175 gc.gridx = 0;
176 gc.gridy = 1;
177 gc.gridwidth = 1;
178 gc.gridheight = 1;
179 gc.fill = GridBagConstraints.HORIZONTAL;
180 gc.weightx = 0.0;
181 gc.weighty = 0.0;
182 gc.insets = new Insets(0,0,10,10);
183 add(new JLabel(tr("Username")), gc);
184 gc.gridx = 1;
185 gc.gridy = 1;
186 gc.weightx = 1.0;
187 add(tfUserName, gc);
188 gc.gridx = 0;
189 gc.gridy = 2;
190 gc.weightx = 0.0;
191 add(new JLabel(tr("Password")), gc);
192
193 gc.gridx = 1;
194 gc.gridy = 2;
195 gc.weightx = 0.0;
196 add(tfPassword, gc);
197
198 gc.gridx = 0;
199 gc.gridy = 3;
200 gc.gridwidth = 2;
201 gc.gridheight = 1;
202 gc.fill = GridBagConstraints.BOTH;
203 gc.weightx = 1.0;
204 gc.weighty = 0.0;
205 lblWarning = new JMultilineLabel("");
206 lblWarning.setFont(lblWarning.getFont().deriveFont(Font.ITALIC));
207 add(lblWarning, gc);
208
209 gc.gridx = 0;
210 gc.gridy = 4;
211 gc.weighty = 0.0;
212 add(cbSaveCredentials, gc);
213
214 // consume the remaining space
215 gc.gridx = 0;
216 gc.gridy = 5;
217 gc.weighty = 1.0;
218 add(new JPanel(),gc);
219
220 }
221
222 public CredentialPanel(CredentialDialog owner) {
223 this.owner = owner;
224 }
225
226 public void init(String username, String password) {
227 username = username == null ? "" : username;
228 password = password == null ? "" : password;
229 tfUserName.setText(username);
230 tfPassword.setText(password);
231 cbSaveCredentials.setSelected(!username.equals("") && ! password.equals(""));
232 }
233
234 public void startUserInput() {
235 tfUserName.requestFocusInWindow();
236 }
237
238 public String getUserName() {
239 return tfUserName.getText();
240 }
241
242 public char[] getPassword() {
243 return tfPassword.getPassword();
244 }
245
246 public boolean isSaveCredentials() {
247 return cbSaveCredentials.isSelected();
248 }
249 }
250
251 private static class OsmApiCredentialsPanel extends CredentialPanel {
252
253 @Override
254 protected void build() {
255 super.build();
256 tfUserName.setToolTipText(tr("Please enter the user name of your OSM account"));
257 tfPassword.setToolTipText(tr("Please enter the password of your OSM account"));
258 lblHeading.setText(
259 "<html>" + tr("Authenticating at the OSM API ''{0}'' failed. Please enter a valid username and a valid password.",
260 OsmApi.getOsmApi().getBaseUrl()) + "</html>");
261 lblWarning.setText(tr("Warning: The password is transferred unencrypted."));
262 }
263
264 public OsmApiCredentialsPanel(CredentialDialog owner) {
265 super(owner);
266 build();
267 }
268 }
269
270 private static class OtherHostCredentialsPanel extends CredentialPanel {
271
272 String host;
273
274 @Override
275 protected void build() {
276 super.build();
277 tfUserName.setToolTipText(tr("Please enter the user name of your account"));
278 tfPassword.setToolTipText(tr("Please enter the password of your account"));
279 lblHeading.setText(
280 "<html>" + tr("Authenticating at the host ''{0}'' failed. Please enter a valid username and a valid password.",
281 host) + "</html>");
282 lblWarning.setText(tr("Warning: The password is transferred unencrypted."));
283 }
284
285 public OtherHostCredentialsPanel(CredentialDialog owner, String host) {
286 super(owner);
287 this.host = host;
288 build();
289 }
290 }
291
292 private static class HttpProxyCredentialsPanel extends CredentialPanel {
293 @Override
294 protected void build() {
295 super.build();
296 tfUserName.setToolTipText(tr("Please enter the user name for authenticating at your proxy server"));
297 tfPassword.setToolTipText(tr("Please enter the password for authenticating at your proxy server"));
298 lblHeading.setText(
299 "<html>" + tr("Authenticating at the HTTP proxy ''{0}'' failed. Please enter a valid username and a valid password.",
300 Main.pref.get(ProxyPreferencesPanel.PROXY_HTTP_HOST) + ":" + Main.pref.get(ProxyPreferencesPanel.PROXY_HTTP_PORT)) + "</html>");
301 lblWarning.setText("<html>" + tr("Warning: depending on the authentication method the proxy server uses the password may be transferred unencrypted.") + "</html>");
302 }
303
304 public HttpProxyCredentialsPanel(CredentialDialog owner) {
305 super(owner);
306 build();
307 }
308 }
309
310 static private class SelectAllOnFocusHandler extends FocusAdapter {
311 @Override
312 public void focusGained(FocusEvent e) {
313 if (e.getSource() instanceof JTextField) {
314 JTextField tf = (JTextField)e.getSource();
315 tf.selectAll();
316 }
317 }
318 }
319
320 /**
321 * Listener for username and password text fields key events.
322 * When user presses Enter:
323 * If current text field is empty (or just contains a sequence of spaces), nothing happens (or all spaces become selected).
324 * If current text field is not empty, but the next one is (or just contains a sequence of spaces), focuses the next text field.
325 * If both text fields contain characters, submits the form by calling owner's {@link OKAction}.
326 */
327 static private class TFKeyListener implements KeyListener{
328 protected CredentialDialog owner; // owner Dependency Injection to call OKAction
329 protected JTextField currentTF;
330 protected JTextField nextTF;
331
332 public TFKeyListener (CredentialDialog owner, JTextField currentTF, JTextField nextTF)
333 {
334 this.owner = owner;
335 this.currentTF = currentTF;
336 this.nextTF = nextTF;
337 }
338
339 @Override
340 public void keyPressed(KeyEvent e) {
341 if(e.getKeyChar() == KeyEvent.VK_ENTER) {
342 if (currentTF.getText().trim().isEmpty()) {
343 currentTF.selectAll();
344 return;
345 } else if (nextTF.getText().trim().isEmpty()) {
346 nextTF.requestFocusInWindow();
347 nextTF.selectAll();
348 return;
349 } else {
350 OKAction okAction = owner.new OKAction();
351 okAction.actionPerformed(null);
352 }
353 }
354 }
355
356 @Override
357 public void keyReleased ( KeyEvent e ){
358 }
359
360 @Override
361 public void keyTyped ( KeyEvent e ){
362 }
363 }
364
365 class OKAction extends AbstractAction {
366 public OKAction() {
367 putValue(NAME, tr("Authenticate"));
368 putValue(SHORT_DESCRIPTION, tr("Authenticate with the supplied username and password"));
369 putValue(SMALL_ICON, ImageProvider.get("ok"));
370 }
371
372 @Override
373 public void actionPerformed(ActionEvent arg0) {
374 setCanceled(false);
375 setVisible(false);
376 }
377 }
378
379 class CancelAction extends AbstractAction {
380 public CancelAction() {
381 putValue(NAME, tr("Cancel"));
382 putValue(SHORT_DESCRIPTION, tr("Cancel authentication"));
383 putValue(SMALL_ICON, ImageProvider.get("cancel"));
384 }
385
386 public void cancel() {
387 setCanceled(true);
388 setVisible(false);
389 }
390
391 @Override
392 public void actionPerformed(ActionEvent arg0) {
393 cancel();
394 }
395 }
396
397 class WindowEventHander extends WindowAdapter {
398
399 @Override
400 public void windowActivated(WindowEvent e) {
401 if (pnlCredentials != null) {
402 pnlCredentials.startUserInput();
403 }
404 }
405
406 @Override
407 public void windowClosing(WindowEvent e) {
408 new CancelAction().cancel();
409 }
410 }
411}
Note: See TracBrowser for help on using the repository browser.