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

Last change on this file since 12854 was 12854, checked in by bastiK, 7 years ago

see #15229 - fix checkstyle warnings

  • Property svn:eol-style set to native
File size: 17.0 KB
RevLine 
[2711]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;
[10173]16import java.awt.event.KeyAdapter;
[2711]17import java.awt.event.KeyEvent;
18import java.awt.event.WindowAdapter;
19import java.awt.event.WindowEvent;
[12821]20import java.net.Authenticator.RequestorType;
[7083]21import java.util.Objects;
[2711]22
23import javax.swing.AbstractAction;
24import javax.swing.BorderFactory;
25import javax.swing.JCheckBox;
26import javax.swing.JDialog;
27import javax.swing.JLabel;
28import javax.swing.JPanel;
29import javax.swing.JTextField;
30
31import org.openstreetmap.josm.Main;
32import org.openstreetmap.josm.gui.SideButton;
33import org.openstreetmap.josm.gui.help.ContextSensitiveHelpAction;
34import org.openstreetmap.josm.gui.help.HelpUtil;
[12821]35import org.openstreetmap.josm.gui.util.GuiHelper;
[12678]36import org.openstreetmap.josm.gui.util.WindowGeometry;
[6340]37import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
[5752]38import org.openstreetmap.josm.gui.widgets.JosmPasswordField;
[8038]39import org.openstreetmap.josm.gui.widgets.JosmTextField;
[12805]40import org.openstreetmap.josm.io.DefaultProxySelector;
[2711]41import org.openstreetmap.josm.io.OsmApi;
[12821]42import org.openstreetmap.josm.io.auth.AbstractCredentialsAgent;
43import org.openstreetmap.josm.io.auth.CredentialsAgentResponse;
[12846]44import org.openstreetmap.josm.spi.preferences.Config;
[2711]45import org.openstreetmap.josm.tools.ImageProvider;
[10791]46import org.openstreetmap.josm.tools.InputMapUtils;
[12620]47import org.openstreetmap.josm.tools.Logging;
[2711]48
[12452]49/**
50 * Dialog box to request username and password from the user.
51 *
52 * The credentials can be for the OSM API (basic authentication), a different
53 * host or an HTTP proxy.
54 */
[2711]55public class CredentialDialog extends JDialog {
56
[8509]57 public static CredentialDialog getOsmApiCredentialDialog(String username, String password, String host,
58 String saveUsernameAndPasswordCheckboxText) {
[4249]59 CredentialDialog dialog = new CredentialDialog(saveUsernameAndPasswordCheckboxText);
[7083]60 if (Objects.equals(OsmApi.getOsmApi().getHost(), host)) {
[4690]61 dialog.prepareForOsmApiCredentials(username, password);
62 } else {
63 dialog.prepareForOtherHostCredentials(username, password, host);
64 }
[2711]65 dialog.pack();
66 return dialog;
67 }
68
[8509]69 public static CredentialDialog getHttpProxyCredentialDialog(String username, String password, String host,
70 String saveUsernameAndPasswordCheckboxText) {
[4249]71 CredentialDialog dialog = new CredentialDialog(saveUsernameAndPasswordCheckboxText);
[2711]72 dialog.prepareForProxyCredentials(username, password);
73 dialog.pack();
74 return dialog;
75 }
76
[12821]77 /**
78 * Prompts the user (in the EDT) for credentials and fills the given response with what has been entered.
79 * @param requestorType type of the entity requesting authentication
80 * @param agent the credentials agent requesting credentials
81 * @param response authentication response to fill
82 * @param username the known username, if any. Likely to be empty
83 * @param password the known password, if any. Likely to be empty
84 * @param host the host against authentication will be performed
85 * @since 12821
86 */
87 public static void promptCredentials(RequestorType requestorType, AbstractCredentialsAgent agent, CredentialsAgentResponse response,
88 String username, String password, String host) {
89 GuiHelper.runInEDTAndWait(() -> {
90 CredentialDialog dialog;
91 if (requestorType.equals(RequestorType.PROXY))
92 dialog = getHttpProxyCredentialDialog(
93 username, password, host, agent.getSaveUsernameAndPasswordCheckboxText());
94 else
95 dialog = getOsmApiCredentialDialog(
96 username, password, host, agent.getSaveUsernameAndPasswordCheckboxText());
97 dialog.setVisible(true);
98 response.setCanceled(dialog.isCanceled());
99 if (dialog.isCanceled())
100 return;
101 response.setUsername(dialog.getUsername());
102 response.setPassword(dialog.getPassword());
103 response.setSaveCredentials(dialog.isSaveCredentials());
104 });
105 }
106
[2711]107 private boolean canceled;
[4645]108 protected CredentialPanel pnlCredentials;
[9078]109 private final String saveUsernameAndPasswordCheckboxText;
[2711]110
111 public boolean isCanceled() {
112 return canceled;
113 }
114
115 protected void setCanceled(boolean canceled) {
116 this.canceled = canceled;
117 }
118
119 @Override
120 public void setVisible(boolean visible) {
121 if (visible) {
[8510]122 WindowGeometry.centerInWindow(Main.parent, new Dimension(350, 300)).applySafe(this);
[2711]123 }
124 super.setVisible(visible);
125 }
126
127 protected JPanel createButtonPanel() {
128 JPanel pnl = new JPanel(new FlowLayout());
129 pnl.add(new SideButton(new OKAction()));
130 pnl.add(new SideButton(new CancelAction()));
[3770]131 pnl.add(new SideButton(new ContextSensitiveHelpAction(HelpUtil.ht("/Dialog/Password"))));
[2711]132 return pnl;
133 }
134
135 protected void build() {
136 getContentPane().setLayout(new BorderLayout());
137 getContentPane().add(createButtonPanel(), BorderLayout.SOUTH);
138
139 addWindowListener(new WindowEventHander());
[10791]140 InputMapUtils.addEscapeAction(getRootPane(), new CancelAction());
[2711]141
[8510]142 getRootPane().setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
[2711]143 }
144
[4249]145 public CredentialDialog(String saveUsernameAndPasswordCheckboxText) {
146 this.saveUsernameAndPasswordCheckboxText = saveUsernameAndPasswordCheckboxText;
[3501]147 setModalityType(ModalityType.DOCUMENT_MODAL);
[2711]148 try {
149 setAlwaysOnTop(true);
[8510]150 } catch (SecurityException e) {
[12620]151 Logging.log(Logging.LEVEL_WARN, tr("Failed to put Credential Dialog always on top. Caught security exception."), e);
[2711]152 }
153 build();
154 }
155
156 public void prepareForOsmApiCredentials(String username, String password) {
157 setTitle(tr("Enter credentials for OSM API"));
[10179]158 pnlCredentials = new OsmApiCredentialsPanel(this);
159 getContentPane().add(pnlCredentials, BorderLayout.CENTER);
[2711]160 pnlCredentials.init(username, password);
161 validate();
162 }
163
[4690]164 public void prepareForOtherHostCredentials(String username, String password, String host) {
165 setTitle(tr("Enter credentials for host"));
[10179]166 pnlCredentials = new OtherHostCredentialsPanel(this, host);
167 getContentPane().add(pnlCredentials, BorderLayout.CENTER);
[4690]168 pnlCredentials.init(username, password);
169 validate();
170 }
171
[2711]172 public void prepareForProxyCredentials(String username, String password) {
173 setTitle(tr("Enter credentials for HTTP proxy"));
[10179]174 pnlCredentials = new HttpProxyCredentialsPanel(this);
175 getContentPane().add(pnlCredentials, BorderLayout.CENTER);
[2711]176 pnlCredentials.init(username, password);
177 validate();
178 }
179
180 public String getUsername() {
[10179]181 if (pnlCredentials == null)
182 return null;
[2711]183 return pnlCredentials.getUserName();
184 }
185
186 public char[] getPassword() {
[10179]187 if (pnlCredentials == null)
188 return null;
[2711]189 return pnlCredentials.getPassword();
190 }
191
192 public boolean isSaveCredentials() {
[10179]193 if (pnlCredentials == null)
194 return false;
[2711]195 return pnlCredentials.isSaveCredentials();
196 }
197
[4645]198 protected static class CredentialPanel extends JPanel {
[8038]199 protected JosmTextField tfUserName;
[5886]200 protected JosmPasswordField tfPassword;
[2711]201 protected JCheckBox cbSaveCredentials;
[10179]202 protected final JMultilineLabel lblHeading = new JMultilineLabel("");
203 protected final JMultilineLabel lblWarning = new JMultilineLabel("");
[4110]204 protected CredentialDialog owner; // owner Dependency Injection to use Key listeners for username and password text fields
[2711]205
206 protected void build() {
[8038]207 tfUserName = new JosmTextField(20);
[5752]208 tfPassword = new JosmPasswordField(20);
[2711]209 tfUserName.addFocusListener(new SelectAllOnFocusHandler());
210 tfPassword.addFocusListener(new SelectAllOnFocusHandler());
[4110]211 tfUserName.addKeyListener(new TFKeyListener(owner, tfUserName, tfPassword));
212 tfPassword.addKeyListener(new TFKeyListener(owner, tfPassword, tfUserName));
[9776]213 cbSaveCredentials = new JCheckBox(owner != null ? owner.saveUsernameAndPasswordCheckboxText : "");
[2711]214
215 setLayout(new GridBagLayout());
216 GridBagConstraints gc = new GridBagConstraints();
217 gc.gridwidth = 2;
218 gc.gridheight = 1;
219 gc.fill = GridBagConstraints.HORIZONTAL;
220 gc.weightx = 1.0;
221 gc.weighty = 0.0;
[8510]222 gc.insets = new Insets(0, 0, 10, 0);
[10179]223 add(lblHeading, gc);
[2711]224
225 gc.gridx = 0;
226 gc.gridy = 1;
227 gc.gridwidth = 1;
228 gc.gridheight = 1;
229 gc.fill = GridBagConstraints.HORIZONTAL;
230 gc.weightx = 0.0;
231 gc.weighty = 0.0;
[8510]232 gc.insets = new Insets(0, 0, 10, 10);
[2711]233 add(new JLabel(tr("Username")), gc);
234 gc.gridx = 1;
235 gc.gridy = 1;
236 gc.weightx = 1.0;
237 add(tfUserName, gc);
238 gc.gridx = 0;
239 gc.gridy = 2;
240 gc.weightx = 0.0;
241 add(new JLabel(tr("Password")), gc);
242
243 gc.gridx = 1;
244 gc.gridy = 2;
245 gc.weightx = 0.0;
246 add(tfPassword, gc);
247
248 gc.gridx = 0;
249 gc.gridy = 3;
250 gc.gridwidth = 2;
251 gc.gridheight = 1;
252 gc.fill = GridBagConstraints.BOTH;
253 gc.weightx = 1.0;
254 gc.weighty = 0.0;
255 lblWarning.setFont(lblWarning.getFont().deriveFont(Font.ITALIC));
256 add(lblWarning, gc);
257
258 gc.gridx = 0;
259 gc.gridy = 4;
260 gc.weighty = 0.0;
261 add(cbSaveCredentials, gc);
262
263 // consume the remaining space
264 gc.gridx = 0;
265 gc.gridy = 5;
266 gc.weighty = 1.0;
[8510]267 add(new JPanel(), gc);
[2711]268
269 }
270
[4110]271 public CredentialPanel(CredentialDialog owner) {
272 this.owner = owner;
[2711]273 }
274
275 public void init(String username, String password) {
276 username = username == null ? "" : username;
277 password = password == null ? "" : password;
278 tfUserName.setText(username);
279 tfPassword.setText(password);
[6087]280 cbSaveCredentials.setSelected(!username.isEmpty() && !password.isEmpty());
[2711]281 }
282
283 public void startUserInput() {
284 tfUserName.requestFocusInWindow();
285 }
286
287 public String getUserName() {
288 return tfUserName.getText();
289 }
290
291 public char[] getPassword() {
292 return tfPassword.getPassword();
293 }
294
295 public boolean isSaveCredentials() {
296 return cbSaveCredentials.isSelected();
297 }
[6885]298
299 protected final void updateWarningLabel(String url) {
300 boolean https = url != null && url.startsWith("https");
301 if (https) {
302 lblWarning.setText(null);
303 } else {
304 lblWarning.setText(tr("Warning: The password is transferred unencrypted."));
305 }
306 lblWarning.setVisible(!https);
307 }
[2711]308 }
309
310 private static class OsmApiCredentialsPanel extends CredentialPanel {
311
312 @Override
313 protected void build() {
314 super.build();
315 tfUserName.setToolTipText(tr("Please enter the user name of your OSM account"));
[2915]316 tfPassword.setToolTipText(tr("Please enter the password of your OSM account"));
[6885]317 String apiUrl = OsmApi.getOsmApi().getBaseUrl();
[2711]318 lblHeading.setText(
[2848]319 "<html>" + tr("Authenticating at the OSM API ''{0}'' failed. Please enter a valid username and a valid password.",
[6885]320 apiUrl) + "</html>");
321 updateWarningLabel(apiUrl);
[2711]322 }
323
[8836]324 OsmApiCredentialsPanel(CredentialDialog owner) {
[4110]325 super(owner);
[2711]326 build();
327 }
328 }
329
[4690]330 private static class OtherHostCredentialsPanel extends CredentialPanel {
331
[9078]332 private final String host;
[4690]333
334 @Override
335 protected void build() {
336 super.build();
337 tfUserName.setToolTipText(tr("Please enter the user name of your account"));
338 tfPassword.setToolTipText(tr("Please enter the password of your account"));
339 lblHeading.setText(
340 "<html>" + tr("Authenticating at the host ''{0}'' failed. Please enter a valid username and a valid password.",
341 host) + "</html>");
[6885]342 updateWarningLabel(host);
[4690]343 }
344
[8836]345 OtherHostCredentialsPanel(CredentialDialog owner, String host) {
[4690]346 super(owner);
347 this.host = host;
348 build();
349 }
350 }
351
[2711]352 private static class HttpProxyCredentialsPanel extends CredentialPanel {
353 @Override
354 protected void build() {
355 super.build();
356 tfUserName.setToolTipText(tr("Please enter the user name for authenticating at your proxy server"));
357 tfPassword.setToolTipText(tr("Please enter the password for authenticating at your proxy server"));
[12854]358 lblHeading.setText("<html>" +
359 tr("Authenticating at the HTTP proxy ''{0}'' failed. Please enter a valid username and a valid password.",
[12846]360 Config.getPref().get(DefaultProxySelector.PROXY_HTTP_HOST) + ':' +
361 Config.getPref().get(DefaultProxySelector.PROXY_HTTP_PORT)) + "</html>");
[8509]362 lblWarning.setText("<html>" +
363 tr("Warning: depending on the authentication method the proxy server uses the password may be transferred unencrypted.")
364 + "</html>");
[2711]365 }
366
[8836]367 HttpProxyCredentialsPanel(CredentialDialog owner) {
[4110]368 super(owner);
[2711]369 build();
370 }
371 }
372
[6889]373 private static class SelectAllOnFocusHandler extends FocusAdapter {
[2711]374 @Override
375 public void focusGained(FocusEvent e) {
376 if (e.getSource() instanceof JTextField) {
[8510]377 JTextField tf = (JTextField) e.getSource();
[2711]378 tf.selectAll();
379 }
380 }
381 }
382
[4110]383 /**
384 * Listener for username and password text fields key events.
385 * When user presses Enter:
386 * If current text field is empty (or just contains a sequence of spaces), nothing happens (or all spaces become selected).
387 * If current text field is not empty, but the next one is (or just contains a sequence of spaces), focuses the next text field.
388 * If both text fields contain characters, submits the form by calling owner's {@link OKAction}.
389 */
[10173]390 private static class TFKeyListener extends KeyAdapter {
[4110]391 protected CredentialDialog owner; // owner Dependency Injection to call OKAction
392 protected JTextField currentTF;
393 protected JTextField nextTF;
394
[8836]395 TFKeyListener(CredentialDialog owner, JTextField currentTF, JTextField nextTF) {
[4110]396 this.owner = owner;
397 this.currentTF = currentTF;
398 this.nextTF = nextTF;
399 }
400
[4249]401 @Override
[4110]402 public void keyPressed(KeyEvent e) {
[8510]403 if (e.getKeyChar() == KeyEvent.VK_ENTER) {
[4110]404 if (currentTF.getText().trim().isEmpty()) {
405 currentTF.selectAll();
406 return;
407 } else if (nextTF.getText().trim().isEmpty()) {
408 nextTF.requestFocusInWindow();
409 nextTF.selectAll();
410 return;
411 } else {
412 OKAction okAction = owner.new OKAction();
413 okAction.actionPerformed(null);
414 }
415 }
416 }
417 }
418
[2711]419 class OKAction extends AbstractAction {
[8836]420 OKAction() {
[2711]421 putValue(NAME, tr("Authenticate"));
422 putValue(SHORT_DESCRIPTION, tr("Authenticate with the supplied username and password"));
423 putValue(SMALL_ICON, ImageProvider.get("ok"));
424 }
425
[4249]426 @Override
[2711]427 public void actionPerformed(ActionEvent arg0) {
428 setCanceled(false);
429 setVisible(false);
430 }
431 }
432
433 class CancelAction extends AbstractAction {
[8836]434 CancelAction() {
[2711]435 putValue(NAME, tr("Cancel"));
436 putValue(SHORT_DESCRIPTION, tr("Cancel authentication"));
437 putValue(SMALL_ICON, ImageProvider.get("cancel"));
438 }
439
440 public void cancel() {
441 setCanceled(true);
442 setVisible(false);
443 }
444
[4249]445 @Override
[2711]446 public void actionPerformed(ActionEvent arg0) {
447 cancel();
448 }
449 }
450
451 class WindowEventHander extends WindowAdapter {
452
453 @Override
454 public void windowActivated(WindowEvent e) {
455 if (pnlCredentials != null) {
456 pnlCredentials.startUserInput();
457 }
458 }
459
460 @Override
461 public void windowClosing(WindowEvent e) {
462 new CancelAction().cancel();
463 }
464 }
465}
Note: See TracBrowser for help on using the repository browser.