Ticket #3112: npm_patch_r1953

File npm_patch_r1953, 17.4 KB (added by bastiK, 3 years ago)
Line 
1Index: src/org/openstreetmap/josm/gui/preferences/ServerAccessPreference.java
2===================================================================
3--- src/org/openstreetmap/josm/gui/preferences/ServerAccessPreference.java      (revision 1953)
4+++ src/org/openstreetmap/josm/gui/preferences/ServerAccessPreference.java      (working copy)
5@@ -11,6 +11,8 @@
6 
7 import org.openstreetmap.josm.Main;
8 import org.openstreetmap.josm.tools.GBC;
9+import org.openstreetmap.josm.io.OsmConnection;
10+import org.openstreetmap.josm.io.CredentialsManager.PreferenceAdditions;
11 
12 public class ServerAccessPreference implements PreferenceSetting {
13 
14@@ -25,41 +27,22 @@
15      */
16     private JTextField osmDataServer = new JTextField(20);
17     /**
18-     * Editfield for the username to the OSM account.
19+     * Provide username and password input editfields.
20+     * Store the values if user hits OK.
21      */
22-    private JTextField osmDataUsername = new JTextField(20);
23-    /**
24-     * Passwordfield for the userpassword of the REST API.
25-     */
26-    private JPasswordField osmDataPassword = new JPasswordField(20);
27+    private PreferenceAdditions credentialsPA = OsmConnection.credentialsManager.newPreferenceAdditions();
28 
29     public void addGui(PreferenceDialog gui) {
30         osmDataServer.setText(Main.pref.get("osm-server.url", "http://api.openstreetmap.org/api"));
31-        osmDataUsername.setText(Main.pref.get("osm-server.username"));
32-        osmDataPassword.setText(Main.pref.get("osm-server.password"));
33-
34         osmDataServer.setToolTipText(tr("The base URL for the OSM server (REST API)"));
35-        osmDataUsername.setToolTipText(tr("Login name (e-mail) to the OSM account."));
36-        osmDataPassword.setToolTipText(tr("Login password to the OSM account. Leave blank to not store any password."));
37-
38         gui.connection.add(new JLabel(tr("Base Server URL")), GBC.std());
39         gui.connection.add(osmDataServer, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
40-        gui.connection.add(new JLabel(tr("OSM username (e-mail)")), GBC.std());
41-        gui.connection.add(osmDataUsername, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
42-        gui.connection.add(new JLabel(tr("OSM password")), GBC.std());
43-        gui.connection.add(osmDataPassword, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,0));
44-        JLabel warning = new JLabel(tr("<html>" +
45-                "WARNING: The password is stored in plain text in the preferences file.<br>" +
46-                "The password is transferred in plain text to the server, encoded in the URL.<br>" +
47-        "<b>Do not use a valuable Password.</b></html>"));
48-        warning.setFont(warning.getFont().deriveFont(Font.ITALIC));
49-        gui.connection.add(warning, GBC.eop().fill(GBC.HORIZONTAL));
50+        credentialsPA.addPreferenceOptions(gui.connection);
51     }
52 
53     public boolean ok() {
54         Main.pref.put("osm-server.url", osmDataServer.getText());
55-        Main.pref.put("osm-server.username", osmDataUsername.getText());
56-        Main.pref.put("osm-server.password", String.valueOf(osmDataPassword.getPassword()));
57+        credentialsPA.preferencesChanged();
58         return false;
59     }
60 }
61Index: src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java
62===================================================================
63--- src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java    (revision 1953)
64+++ src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java    (working copy)
65@@ -40,7 +40,7 @@
66 
67     // some common tabs
68     public final JPanel display = createPreferenceTab("display", tr("Display Settings"), tr("Various settings that influence the visual representation of the whole program."));
69-    public final JPanel connection = createPreferenceTab("connection", I18n.tr("Connection Settings"), I18n.tr("Connection Settings for the OSM server."));
70+    public final JPanel connection = createPreferenceTab("connection", I18n.tr("Connection Settings"), I18n.tr("Connection Settings for the OSM server."),true);
71     public final JPanel map = createPreferenceTab("map", I18n.tr("Map Settings"), I18n.tr("Settings for the map projection and data interpretation."));
72     public final JPanel audio = createPreferenceTab("audio", I18n.tr("Audio Settings"), I18n.tr("Settings for the audio player and audio markers."));
73 
74Index: src/org/openstreetmap/josm/io/CredentialsManager.java
75===================================================================
76--- src/org/openstreetmap/josm/io/CredentialsManager.java       (revision 0)
77+++ src/org/openstreetmap/josm/io/CredentialsManager.java       (revision 0)
78@@ -0,0 +1,54 @@
79+// License: GPL. For details, see LICENSE file.
80+package org.openstreetmap.josm.io;
81+
82+import org.openstreetmap.josm.io.OsmConnection.OsmAuth;
83+
84+/**
85+ * Manages how username and password are stored. In addition all
86+ * username/password-related user interaction is encapsulated here.
87+ */
88+public interface CredentialsManager {
89+    /**
90+     * lookupUsername, lookupPassword:
91+     *
92+     * Should throw or return non-null, possibly empty String.
93+     */
94+    public String lookupUsername() throws CMException;
95+    public String lookupPassword() throws CMException;
96+
97+    /**
98+     * storeUsername, storePassword:
99+     *
100+     * May silently fail to store.
101+     */
102+    public void storeUsername(String username) throws CMException;
103+    public void storePassword(String password) throws CMException;
104+
105+    /**
106+     * If authentication using the stored credentials fails, this method is
107+     * called to promt for new username/password.
108+     */
109+    public java.net.PasswordAuthentication getPasswordAuthentication(OsmAuth caller);
110+
111+    /**
112+     * Credentials-related preference gui.
113+     */
114+    public interface PreferenceAdditions {
115+        public void addPreferenceOptions(javax.swing.JPanel panel);
116+        public void preferencesChanged();
117+    }
118+    public PreferenceAdditions newPreferenceAdditions();
119+
120+    public class CMException extends Exception {
121+        public CMException() {super();}
122+        public CMException(String message, Throwable cause) {super(message, cause);}
123+        public CMException(String message) {super(message);}
124+        public CMException(Throwable cause) {super(cause);}
125+    }
126+    public class NoContentException extends CMException {
127+        public NoContentException() {super();}
128+        public NoContentException(String message, Throwable cause) {super(message, cause);}
129+        public NoContentException(String message) {super(message);}
130+        public NoContentException(Throwable cause) {super(cause);}
131+    }
132+}
133Index: src/org/openstreetmap/josm/io/OsmConnection.java
134===================================================================
135--- src/org/openstreetmap/josm/io/OsmConnection.java    (revision 1953)
136+++ src/org/openstreetmap/josm/io/OsmConnection.java    (working copy)
137@@ -24,6 +24,7 @@
138 import org.openstreetmap.josm.gui.ExtendedDialog;
139 import org.openstreetmap.josm.tools.Base64;
140 import org.openstreetmap.josm.tools.GBC;
141+import org.openstreetmap.josm.io.CredentialsManager.CMException;
142 
143 /**
144  * Base class that handles common things like authentication for the reader and writer
145@@ -35,8 +36,17 @@
146 
147     protected boolean cancel = false;
148     protected HttpURLConnection activeConnection;
149+    /**
150+     * Handles password storage and some related gui-components.
151+     * It can be set by a plugin. This may happen at startup and
152+     * by changing the preferences.
153+     * Syncronize on this object to get or set a consistent
154+     * username/password pair.
155+     */
156+    public static CredentialsManager credentialsManager = new PlainCredentialsManager();
157 
158     private static OsmAuth authentication = new OsmAuth();
159+
160     /**
161      * Initialize the http defaults and the authenticator.
162      */
163@@ -54,58 +64,17 @@
164     /**
165      * The authentication class handling the login requests.
166      */
167-    private static class OsmAuth extends Authenticator {
168+    public static class OsmAuth extends Authenticator {
169         /**
170          * Set to true, when the autenticator tried the password once.
171          */
172-        boolean passwordtried = false;
173+        public boolean passwordtried = false;
174         /**
175          * Whether the user cancelled the password dialog
176          */
177-        boolean authCancelled = false;
178-
179+        public boolean authCancelled = false;
180         @Override protected PasswordAuthentication getPasswordAuthentication() {
181-            String username = Main.pref.get("osm-server.username");
182-            String password = Main.pref.get("osm-server.password");
183-            if (passwordtried || username.equals("") || password.equals("")) {
184-                JPanel p = new JPanel(new GridBagLayout());
185-                if (!username.equals("") && !password.equals("")) {
186-                    p.add(new JLabel(tr("Incorrect password or username.")), GBC.eop());
187-                }
188-                p.add(new JLabel(tr("Username")), GBC.std().insets(0,0,10,0));
189-                JTextField usernameField = new JTextField(username, 20);
190-                p.add(usernameField, GBC.eol());
191-                p.add(new JLabel(tr("Password")), GBC.std().insets(0,0,10,0));
192-                JPasswordField passwordField = new JPasswordField(password, 20);
193-                p.add(passwordField, GBC.eol());
194-                JLabel warning = new JLabel(tr("Warning: The password is transferred unencrypted."));
195-                warning.setFont(warning.getFont().deriveFont(Font.ITALIC));
196-                p.add(warning, GBC.eop());
197-
198-                JCheckBox savePassword = new JCheckBox(tr("Save user and password (unencrypted)"), !username.equals("") && !password.equals(""));
199-                p.add(savePassword, GBC.eop());
200-
201-                int choice = new ExtendedDialog(Main.parent,
202-                        tr("Enter Password"),
203-                        p,
204-                        new String[] {tr("Login"), tr("Cancel")},
205-                        new String[] {"ok.png", "cancel.png"}).getValue();
206-
207-                if (choice != 1) {
208-                    authCancelled = true;
209-                    return null;
210-                }
211-                username = usernameField.getText();
212-                password = String.valueOf(passwordField.getPassword());
213-                if (savePassword.isSelected()) {
214-                    Main.pref.put("osm-server.username", username);
215-                    Main.pref.put("osm-server.password", password);
216-                }
217-                if (username.equals(""))
218-                    return null;
219-            }
220-            passwordtried = true;
221-            return new PasswordAuthentication(username, password.toCharArray());
222+            return credentialsManager.getPasswordAuthentication(this);
223         }
224     }
225 
226@@ -140,7 +109,14 @@
227 
228     protected void addAuth(HttpURLConnection con) throws CharacterCodingException {
229         CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();
230-        String auth = Main.pref.get("osm-server.username") + ":" + Main.pref.get("osm-server.password");
231+        String auth;
232+        try {
233+            synchronized (credentialsManager) {
234+                auth = credentialsManager.lookupUsername() + ":" + credentialsManager.lookupPassword();
235+            }
236+        } catch (CMException e) {
237+            auth = ":";
238+        }
239         ByteBuffer bytes = encoder.encode(CharBuffer.wrap(auth));
240         con.addRequestProperty("Authorization", "Basic "+Base64.encode(bytes));
241     }
242@@ -154,4 +130,125 @@
243     public boolean isCanceled() {
244         return cancel;
245     }
246+
247+    public static class PlainCredentialsManager implements CredentialsManager {
248+        public String lookupUsername() throws CMException {
249+            String username = Main.pref.get("osm-server.username", null);
250+            if (username == null) throw new CredentialsManager.NoContentException();
251+            return username;
252+        }
253+        public String lookupPassword() throws CMException {
254+            String password = Main.pref.get("osm-server.password");
255+            if (password == null) throw new CredentialsManager.NoContentException();
256+            return password;
257+        }
258+        public void storeUsername(String username) {
259+            Main.pref.put("osm-server.username", username);
260+        }
261+        public void storePassword(String password) {
262+            Main.pref.put("osm-server.password", password);
263+        }
264+        public PasswordAuthentication getPasswordAuthentication(OsmAuth caller) {
265+            String username, password;
266+            try {
267+                username = lookupUsername();
268+            } catch (CMException e) {
269+                username = "";
270+            }
271+            try {
272+                password = lookupPassword();
273+            } catch (CMException e) {
274+                password = "";
275+            }
276+            if (caller.passwordtried || username.equals("") || password.equals("")) {
277+                JPanel p = new JPanel(new GridBagLayout());
278+                if (!username.equals("") && !password.equals("")) {
279+                    p.add(new JLabel(tr("Incorrect password or username.")), GBC.eop());
280+                }
281+                p.add(new JLabel(tr("Username")), GBC.std().insets(0,0,10,0));
282+                JTextField usernameField = new JTextField(username, 20);
283+                p.add(usernameField, GBC.eol());
284+                p.add(new JLabel(tr("Password")), GBC.std().insets(0,0,10,0));
285+                JPasswordField passwordField = new JPasswordField(password, 20);
286+                p.add(passwordField, GBC.eol());
287+                JLabel warning = new JLabel(tr("Warning: The password is transferred unencrypted."));
288+                warning.setFont(warning.getFont().deriveFont(Font.ITALIC));
289+                p.add(warning, GBC.eop());
290+
291+                JCheckBox savePassword = new JCheckBox(tr("Save user and password (unencrypted)"), !username.equals("") && !password.equals(""));
292+                p.add(savePassword, GBC.eop());
293+
294+                int choice = new ExtendedDialog(Main.parent,
295+                        tr("Enter Password"),
296+                        p,
297+                        new String[] {tr("Login"), tr("Cancel")},
298+                        new String[] {"ok.png", "cancel.png"}).getValue();
299+
300+                if (choice != 1) {
301+                    caller.authCancelled = true;
302+                    return null;
303+                }
304+                username = usernameField.getText();
305+                password = String.valueOf(passwordField.getPassword());
306+                if (savePassword.isSelected()) {
307+                    storeUsername(username);
308+                    storePassword(password);
309+                }
310+                if (username.equals(""))
311+                    return null;
312+            }
313+            caller.passwordtried = true;
314+            return new PasswordAuthentication(username, password.toCharArray());
315+        }
316+        public PreferenceAdditions newPreferenceAdditions() {
317+            return new PreferenceAdditions() {
318+                /**
319+                 * Editfield for the username to the OSM account.
320+                 */
321+                private JTextField osmDataUsername = new JTextField(20);
322+                /**
323+                 * Passwordfield for the userpassword of the REST API.
324+                 */
325+                private JPasswordField osmDataPassword = new JPasswordField(20);
326+
327+                private String oldUsername = "";
328+                private String oldPassword = "";
329+
330+                public void addPreferenceOptions(JPanel panel) {
331+                    try {
332+                        oldUsername = lookupUsername();
333+                    } catch (CMException e) {
334+                        oldUsername = "";
335+                    }
336+                    try {
337+                        oldPassword = lookupPassword();
338+                    } catch (CMException e) {
339+                        oldPassword = "";
340+                    }
341+                    osmDataUsername.setText(oldUsername);
342+                    osmDataPassword.setText(oldPassword);
343+                    osmDataUsername.setToolTipText(tr("Login name (e-mail) to the OSM account."));
344+                    osmDataPassword.setToolTipText(tr("Login password to the OSM account. Leave blank to not store any password."));
345+                    panel.add(new JLabel(tr("OSM username (e-mail)")), GBC.std());
346+                    panel.add(osmDataUsername, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,5));
347+                    panel.add(new JLabel(tr("OSM password")), GBC.std());
348+                    panel.add(osmDataPassword, GBC.eol().fill(GBC.HORIZONTAL).insets(5,0,0,0));
349+                    JLabel warning = new JLabel(tr("<html>" +
350+                            "WARNING: The password is stored in plain text in the preferences file.<br>" +
351+                            "The password is transferred in plain text to the server, encoded in the URL.<br>" +
352+                            "<b>Do not use a valuable Password.</b></html>"));
353+                    warning.setFont(warning.getFont().deriveFont(Font.ITALIC));
354+                    panel.add(warning, GBC.eop().fill(GBC.HORIZONTAL));
355+                }
356+                public void preferencesChanged() {
357+                    String newUsername = osmDataUsername.getText();
358+                    String newPassword = String.valueOf(osmDataPassword.getPassword());
359+                    if (!oldUsername.equals(newUsername))
360+                        storeUsername(newUsername);
361+                    if (!oldPassword.equals(newPassword))
362+                        storePassword(newPassword);
363+                }
364+            };
365+        }
366+    }
367 }