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

Last change on this file since 5752 was 5752, checked in by Don-vip, 11 years ago

fix #8404 - workaround for JDK bug 6322854 (crash when inserting password from clipboard corrupted by KeePass)

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