source: josm/trunk/src/org/openstreetmap/josm/io/OsmConnection.java@ 2198

Last change on this file since 2198 was 2124, checked in by Gubaer, 15 years ago

See #3483: "Load list of changesets from the server" is broken for users with non-ASCII usernames

  • Property svn:eol-style set to native
File size: 11.4 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Font;
7import java.awt.GridBagLayout;
8import java.net.Authenticator;
9import java.net.HttpURLConnection;
10import java.net.PasswordAuthentication;
11import java.nio.ByteBuffer;
12import java.nio.CharBuffer;
13import java.nio.charset.CharacterCodingException;
14import java.nio.charset.Charset;
15import java.nio.charset.CharsetEncoder;
16import java.util.logging.Logger;
17
18import javax.swing.JCheckBox;
19import javax.swing.JLabel;
20import javax.swing.JPanel;
21import javax.swing.JPasswordField;
22import javax.swing.JTextField;
23
24import org.openstreetmap.josm.Main;
25import org.openstreetmap.josm.gui.ExtendedDialog;
26import org.openstreetmap.josm.tools.Base64;
27import org.openstreetmap.josm.tools.GBC;
28
29/**
30 * Base class that handles common things like authentication for the reader and writer
31 * to the osm server.
32 *
33 * @author imi
34 */
35public class OsmConnection {
36 private static final Logger logger = Logger.getLogger(OsmConnection.class.getName());
37
38 protected boolean cancel = false;
39 protected HttpURLConnection activeConnection;
40 /**
41 * Handles password storage and some related gui-components.
42 * It can be set by a plugin. This may happen at startup and
43 * by changing the preferences.
44 * Syncronize on this object to get or set a consistent
45 * username/password pair.
46 */
47 public static CredentialsManager credentialsManager = new PlainCredentialsManager();
48
49 private static OsmAuth authentication = new OsmAuth();
50
51 /**
52 * Initialize the http defaults and the authenticator.
53 */
54 static {
55 // TODO: current authentication handling is sub-optimal in that it seems to use the same authenticator for
56 // any kind of request. HTTP requests executed by plugins, e.g. to password-protected WMS servers,
57 // will use the same username/password which is undesirable.
58 try {
59 HttpURLConnection.setFollowRedirects(true);
60 Authenticator.setDefault(authentication);
61 } catch (SecurityException e) {
62 }
63 }
64
65 /**
66 * The authentication class handling the login requests.
67 */
68 public static class OsmAuth extends Authenticator {
69 /**
70 * Set to true, when the autenticator tried the password once.
71 */
72 public boolean passwordtried = false;
73 /**
74 * Whether the user cancelled the password dialog
75 */
76 public boolean authCancelled = false;
77 @Override protected PasswordAuthentication getPasswordAuthentication() {
78 return credentialsManager.getPasswordAuthentication(this);
79 }
80 }
81
82 /**
83 * Must be called before each connection attemp to initialize the authentication.
84 */
85 protected final void initAuthentication() {
86 authentication.authCancelled = false;
87 authentication.passwordtried = false;
88 }
89
90 /**
91 * @return Whether the connection was cancelled.
92 */
93 protected final boolean isAuthCancelled() {
94 return authentication.authCancelled;
95 }
96
97 public void cancel() {
98 cancel = true;
99 if (activeConnection != null) {
100 activeConnection.setConnectTimeout(100);
101 activeConnection.setReadTimeout(100);
102 try {
103 Thread.sleep(100);
104 } catch (InterruptedException ex) {}
105 activeConnection.disconnect();
106 }
107 }
108
109 protected void addAuth(HttpURLConnection con) throws CharacterCodingException {
110 CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
111 String auth;
112 try {
113 synchronized (credentialsManager) {
114 auth = credentialsManager.lookup(CredentialsManager.Key.USERNAME) + ":" +
115 credentialsManager.lookup(CredentialsManager.Key.PASSWORD);
116 }
117 } catch (CredentialsManager.CMException e) {
118 auth = ":";
119 }
120 ByteBuffer bytes = encoder.encode(CharBuffer.wrap(auth));
121 con.addRequestProperty("Authorization", "Basic "+Base64.encode(bytes));
122 }
123
124 /**
125 * Replies true if this connection is canceled
126 *
127 * @return true if this connection is canceled
128 * @return
129 */
130 public boolean isCanceled() {
131 return cancel;
132 }
133 /**
134 * Default implementation of the CredentialsManager interface.
135 * Saves passwords in plain text file.
136 */
137 public static class PlainCredentialsManager implements CredentialsManager {
138 public String lookup(CredentialsManager.Key key) throws CMException {
139 String secret = Main.pref.get("osm-server." + key.toString(), null);
140 if (secret == null) throw new CredentialsManager.NoContentException();
141 return secret;
142 }
143 public void store(CredentialsManager.Key key, String secret) {
144 Main.pref.put("osm-server." + key.toString(), secret);
145 }
146 public PasswordAuthentication getPasswordAuthentication(OsmAuth caller) {
147 String username, password;
148 try {
149 username = lookup(Key.USERNAME);
150 } catch (CMException e) {
151 username = "";
152 }
153 try {
154 password = lookup(Key.PASSWORD);
155 } catch (CMException e) {
156 password = "";
157 }
158 if (caller.passwordtried || username.equals("") || password.equals("")) {
159 JPanel p = new JPanel(new GridBagLayout());
160 if (!username.equals("") && !password.equals("")) {
161 p.add(new JLabel(tr("Incorrect password or username.")), GBC.eop());
162 }
163 p.add(new JLabel(tr("Username")), GBC.std().insets(0,0,10,0));
164 JTextField usernameField = new JTextField(username, 20);
165 p.add(usernameField, GBC.eol());
166 p.add(new JLabel(tr("Password")), GBC.std().insets(0,0,10,0));
167 JPasswordField passwordField = new JPasswordField(password, 20);
168 p.add(passwordField, GBC.eol());
169 JLabel warning = new JLabel(tr("Warning: The password is transferred unencrypted."));
170 warning.setFont(warning.getFont().deriveFont(Font.ITALIC));
171 p.add(warning, GBC.eop());
172
173 JCheckBox savePassword = new JCheckBox(tr("Save user and password (unencrypted)"),
174 !username.equals("") && !password.equals(""));
175 p.add(savePassword, GBC.eop());
176
177 ExtendedDialog dialog = new ExtendedDialog(
178 Main.parent,
179 tr("Enter Password"),
180 new String[] {tr("Login"), tr("Cancel")}
181 );
182 dialog.setContent(p);
183 dialog.setButtonIcons( new String[] {"ok.png", "cancel.png"});
184 dialog.showDialog();
185
186 if (dialog.getValue() != 1) {
187 caller.authCancelled = true;
188 return null;
189 }
190 username = usernameField.getText();
191 password = String.valueOf(passwordField.getPassword());
192 if (savePassword.isSelected()) {
193 store(Key.USERNAME, username);
194 store(Key.PASSWORD, password);
195 }
196 if (username.equals(""))
197 return null;
198 }
199 caller.passwordtried = true;
200 return new PasswordAuthentication(username, password.toCharArray());
201 }
202 public PreferenceAdditions newPreferenceAdditions() {
203 return new PreferenceAdditions() {
204 /**
205 * Editfield for the Base url to the REST API from OSM.
206 */
207 final private JTextField osmDataServerURL = new JTextField(20);
208 /**
209 * Editfield for the username to the OSM account.
210 */
211 final private JTextField osmDataUsername = new JTextField(20);
212 /**
213 * Passwordfield for the userpassword of the REST API.
214 */
215 final private JPasswordField osmDataPassword = new JPasswordField(20);
216
217 private String oldServerURL = "";
218 private String oldUsername = "";
219 private String oldPassword = "";
220
221 public void addPreferenceOptions(JPanel panel) {
222 try {
223 oldServerURL = lookup(Key.OSM_SERVER_URL); // result is not null (see CredentialsManager)
224 } catch (CMException e) {
225 oldServerURL = "";
226 }
227 if (oldServerURL.equals("")) {
228 oldServerURL = "http://api.openstreetmap.org/api";
229 }
230 try {
231 oldUsername = lookup(Key.USERNAME);
232 } catch (CMException e) {
233 oldUsername = "";
234 }
235 try {
236 oldPassword = lookup(Key.PASSWORD);
237 } catch (CMException e) {
238 oldPassword = "";
239 }
240 osmDataServerURL.setText(oldServerURL);
241 osmDataUsername.setText(oldUsername);
242 osmDataPassword.setText(oldPassword);
243 osmDataServerURL.setToolTipText(tr("The base URL for the OSM server (REST API)"));
244 osmDataUsername.setToolTipText(tr("Login name (e-mail) to the OSM account."));
245 osmDataPassword.setToolTipText(tr("Login password to the OSM account. Leave blank to not store any password."));
246 panel.add(new JLabel(tr("Base Server URL")), GBC.std());
247 panel.add(osmDataServerURL, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
248 panel.add(new JLabel(tr("OSM username (e-mail)")), GBC.std());
249 panel.add(osmDataUsername, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
250 panel.add(new JLabel(tr("OSM password")), GBC.std());
251 panel.add(osmDataPassword, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,0));
252 JLabel warning = new JLabel(tr("<html>" +
253 "WARNING: The password is stored in plain text in the preferences file.<br>" +
254 "The password is transferred in plain text to the server, encoded in the URL.<br>" +
255 "<b>Do not use a valuable Password.</b></html>"));
256 warning.setFont(warning.getFont().deriveFont(Font.ITALIC));
257 panel.add(warning, GBC.eop().fill(GBC.HORIZONTAL));
258 }
259 public void preferencesChanged() {
260 String newServerURL = osmDataServerURL.getText();
261 String newUsername = osmDataUsername.getText();
262 String newPassword = String.valueOf(osmDataPassword.getPassword());
263 if (!oldServerURL.equals(newServerURL)) {
264 store(Key.OSM_SERVER_URL, newServerURL);
265 }
266 if (!oldUsername.equals(newUsername)) {
267 store(Key.USERNAME, newUsername);
268 }
269 if (!oldPassword.equals(newPassword)) {
270 store(Key.PASSWORD, newPassword);
271 }
272 }
273 };
274 }
275 }
276}
Note: See TracBrowser for help on using the repository browser.