Ticket #2710: initial_multiuser_rework_v2.patch
File initial_multiuser_rework_v2.patch, 47.9 KB (added by , 6 years ago) |
---|
-
src/org/openstreetmap/josm/data/UserIdentityManager.java
4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 6 import java.text.MessageFormat; 7 import java.util.ArrayList; 8 import java.util.LinkedHashMap; 9 import java.util.List; 10 import java.util.Map; 11 import java.util.TreeMap; 7 12 8 13 import org.openstreetmap.josm.data.oauth.OAuthAccessTokenHolder; 9 14 import org.openstreetmap.josm.data.osm.User; … … 14 19 import org.openstreetmap.josm.io.OsmApi; 15 20 import org.openstreetmap.josm.io.OsmServerUserInfoReader; 16 21 import org.openstreetmap.josm.io.OsmTransferException; 22 import org.openstreetmap.josm.io.auth.CredentialsAgentResponse; 17 23 import org.openstreetmap.josm.io.auth.CredentialsManager; 18 24 import org.openstreetmap.josm.spi.preferences.Config; 19 25 import org.openstreetmap.josm.spi.preferences.PreferenceChangeEvent; … … 78 84 instance.initFromPreferences(); 79 85 } 80 86 Config.getPref().addPreferenceChangeListener(instance); 87 instance.populateAllUsers(); 81 88 } 82 89 return instance; 83 90 } 84 91 85 private String userName;86 private UserInfo userInfo;87 92 private boolean accessTokenKeyChanged; 88 93 private boolean accessTokenSecretChanged; 89 94 95 private String userName; 96 private UserInfo userInfo; 97 private LinkedHashMap<String, UserInfo> users; 98 90 99 private UserIdentityManager() { 100 users = new LinkedHashMap<>(); 91 101 } 92 102 93 103 /** … … 112 122 if (trimmedUserName.isEmpty()) 113 123 throw new IllegalArgumentException( 114 124 MessageFormat.format("Expected non-empty value for parameter ''{0}'', got ''{1}''", "userName", userName)); 115 this.userName = trimmedUserName;125 userName = trimmedUserName; 116 126 userInfo = null; 117 127 } 118 128 … … 132 142 if (trimmedUserName.isEmpty()) 133 143 throw new IllegalArgumentException(tr("Expected non-empty value for parameter ''{0}'', got ''{1}''", "userName", userName)); 134 144 CheckParameterUtil.ensureParameterNotNull(userInfo, "userInfo"); 135 this.userName = trimmedUserName;145 userName = trimmedUserName; 136 146 this.userInfo = userInfo; 137 147 } 138 148 … … 238 248 } 239 249 240 250 /** 251 * Initializes the user identity manager from OAuth request of user details. 252 * @param oauth The {@code OAuthAccessTokenHolder} with the key and secret 253 * @see #initFromPreferences 254 * @since xxx 255 */ 256 public void initFromOauth(OAuthAccessTokenHolder oauth) { 257 try { 258 OsmServerUserInfoReader osmServerReader = new OsmServerUserInfoReader(); 259 UserInfo info = osmServerReader.fetchUserInfo(NullProgressMonitor.INSTANCE, oauth); 260 setFullyIdentified(info.getDisplayName(), info); 261 } catch (IllegalArgumentException | OsmTransferException e) { 262 Logging.error(e); 263 } 264 } 265 266 private List<Map<String, String>> getDefaultOAuthList() { 267 Map<String, String> variables = new TreeMap<>(); 268 TreeMap<String, String> vars = new TreeMap<>(); 269 vars.put("url", "osm-server.url"); 270 vars.put("login", "oauth.access-token.key"); 271 vars.put("password", "oauth.access-token.secret"); 272 vars.put("login-token-url", "oauth.settings.authorise-token-url"); 273 vars.put("auth-url", "oauth.settings.authorise-url"); 274 vars.put("consumer-key", "oauth.settings.consumer-key"); 275 vars.put("consumer-secret", "oauth.settings.consumer-secret"); 276 vars.put("login-url", "oauth.settings.osm-login-url"); 277 vars.put("logout-url", "oauth.settings.osm-logout-url"); 278 variables.put("auth-type", "oauth"); 279 280 vars.forEach((key, value) -> variables.put(key, Config.getPref().get(value))); 281 List<Map<String, String>> rList = new ArrayList<>(); 282 rList.add(variables); 283 return rList; 284 } 285 286 private List<Map<String, String>> getDefaultBasicAuthList() { 287 Map<String, String> variables = new TreeMap<>(); 288 TreeMap<String, String> vars = new TreeMap<>(); 289 290 vars.put("url", "osm-server-url"); 291 vars.put("login", "osm-server.username"); 292 vars.put("password", "osm-server.password"); 293 294 variables.put("auth-type", "basic"); 295 vars.forEach((key, value) -> variables.put(key, Config.getPref().get(value))); 296 List<Map<String, String>> rList = new ArrayList<>(); 297 return rList; 298 } 299 300 private List<Map<String, String>> getDefaultAuthList() { 301 if ("oauth".equals(Config.getPref().get("osm-server.auth-method"))) { 302 return getDefaultOAuthList(); 303 } else { 304 return getDefaultBasicAuthList(); 305 } 306 } 307 308 /** 309 * Populate the users 310 * @since xxx 311 */ 312 public void populateAllUsers() { 313 List<Map<String, String>> authList = Config.getPref().getListOfMaps("all-authorizations", getDefaultAuthList()); 314 for (Map<String, String> map : authList) { // TODO fix 315 if ("oauth".equals(map.get("auth-type"))) { 316 OAuthAccessTokenHolder oauth = new OAuthAccessTokenHolder(); 317 oauth.setAccessToken(map.get("login"), map.get("password")); 318 oauth.setOsmApi(map.get("url")); 319 instance.initFromOauth(oauth); 320 users.put(getUserName(), getUserInfo()); 321 } else if ("basic".equals(map.get("auth-type"))) { 322 CredentialsAgentResponse response = new CredentialsAgentResponse(); 323 response.setUsername(map.get("login")); 324 response.setPassword(map.get("password").toCharArray()); 325 } 326 } 327 328 if (OsmApi.isUsingOAuth() && OAuthAccessTokenHolder.getInstance().containsAccessToken() && 329 !NetworkManager.isOffline(OnlineResource.OSM_API)) { 330 try { 331 instance.initFromOAuth(); 332 } catch (JosmRuntimeException | IllegalArgumentException | IllegalStateException e) { 333 Logging.error(e); 334 // Fall back to preferences if OAuth identification fails for any reason 335 instance.initFromPreferences(); 336 } 337 } else { 338 instance.initFromPreferences(); 339 } 340 } 341 342 /** 241 343 * Replies true if the user with name <code>username</code> is the current user 242 344 * 243 345 * @param userName the user name … … 264 366 } 265 367 } 266 368 369 /** 370 * Get all information on all users that have logged in to JOSM 371 * @return A {@code HashMap} with username/UserInfo pairs. 372 * @since xxx 373 */ 374 public Map<String, UserInfo> getAllUserInformation() { 375 if (users == null) { 376 populateAllUsers(); 377 } 378 return users; 379 } 380 381 /** 382 * Get user authentication information 383 * @return The user information (passwords are protected) 384 * @since xxx 385 */ 386 public List<Map<String, String>> getUserAuthInformation() { 387 List<Map<String, String>> authList = Config.getPref().getListOfMaps("all-authorizations", getDefaultAuthList()); 388 for (Map<String, String> map : authList) { 389 if ("basic".equals(map.get("auth-type"))) { 390 // TODO protect passwords, even though they are stored in plain text 391 // map.put("password", "PROTECTED"); 392 } 393 } 394 return authList; 395 } 396 267 397 /* ------------------------------------------------------------------- */ 268 398 /* interface PreferenceChangeListener */ 269 399 /* ------------------------------------------------------------------- */ -
src/org/openstreetmap/josm/data/oauth/OAuthAccessTokenHolder.java
3 3 4 4 import static org.openstreetmap.josm.tools.I18n.tr; 5 5 6 import java.util.List; 7 import java.util.Map; 8 import java.util.TreeMap; 9 10 import org.openstreetmap.josm.data.UserIdentityManager; 11 import org.openstreetmap.josm.io.OsmApi; 6 12 import org.openstreetmap.josm.io.auth.CredentialsAgent; 7 13 import org.openstreetmap.josm.io.auth.CredentialsAgentException; 8 14 import org.openstreetmap.josm.spi.preferences.Config; … … 16 22 public class OAuthAccessTokenHolder { 17 23 private static OAuthAccessTokenHolder instance; 18 24 25 private OsmApi osmApi = OsmApi.getOsmApi(); 26 19 27 /** 20 28 * Replies the unique instance. 21 29 * @return The unique instance of {@code OAuthAccessTokenHolder} … … 183 191 Logging.warn(tr("Failed to store OAuth Access Token to credentials manager")); 184 192 Logging.warn(tr("Current credential manager is of type ''{0}''", cm.getClass().getName())); 185 193 } 194 List<Map<String, String>> users = UserIdentityManager.getInstance().getUserAuthInformation(); 195 boolean present = false; 196 for (Map<String, String> user : users) { 197 if ("oauth".equals(user.get("auth-type")) && accessTokenKey.equals(user.get("auth-type"))) { 198 user.put("password", accessTokenSecret); 199 user.put("url", osmApi.getHost()); 200 present = true; 201 break; 202 } 203 } 204 if (!present) { 205 Map<String, String> map = new TreeMap<>(); 206 map.put("login", accessTokenKey); 207 map.put("password", accessTokenSecret); 208 map.put("url", osmApi.getHost()); 209 } 186 210 } 187 211 188 212 /** 213 * Set the API to use with the user 214 * @param serverUrl The URL for the OSM server 215 * @since xxx 216 */ 217 public void setOsmApi(String serverUrl) { 218 osmApi = OsmApi.getOsmApi(serverUrl); 219 } 220 221 /** 222 * Get the osmApi for use with this oauth object 223 * @return The OsmApi to use 224 */ 225 public OsmApi getOsmApi() { 226 return osmApi; 227 } 228 229 /** 189 230 * Clears the content of this holder 190 231 */ 191 232 public void clear() { -
src/org/openstreetmap/josm/gui/io/UploadParameterSummaryPanel.java
5 5 import static org.openstreetmap.josm.tools.I18n.trn; 6 6 7 7 import java.awt.BorderLayout; 8 import java.awt.event.ItemEvent; 9 import java.awt.event.ItemListener; 8 10 import java.beans.PropertyChangeEvent; 9 11 import java.beans.PropertyChangeListener; 12 import java.util.Map; 10 13 import java.util.Optional; 11 14 12 15 import javax.swing.BorderFactory; 16 import javax.swing.DefaultComboBoxModel; 17 import javax.swing.JComboBox; 13 18 import javax.swing.JLabel; 14 19 import javax.swing.JPanel; 15 20 import javax.swing.event.HyperlinkEvent; 16 21 import javax.swing.event.HyperlinkListener; 17 22 23 import org.openstreetmap.josm.data.UserIdentityManager; 18 24 import org.openstreetmap.josm.data.osm.Changeset; 25 import org.openstreetmap.josm.data.osm.UserInfo; 19 26 import org.openstreetmap.josm.gui.widgets.JMultilineLabel; 20 27 import org.openstreetmap.josm.io.Capabilities; 21 28 import org.openstreetmap.josm.io.OsmApi; … … 22 29 import org.openstreetmap.josm.io.UploadStrategySpecification; 23 30 import org.openstreetmap.josm.spi.preferences.Config; 24 31 import org.openstreetmap.josm.tools.ImageProvider; 32 import org.openstreetmap.josm.tools.Logging; 25 33 26 34 /** 27 35 * A panel that displays a summary of data the user is about to upload … … 114 122 return msg; 115 123 } 116 124 125 protected JComboBox<String> buildPossibleUserBox() { 126 DefaultComboBoxModel<String> model = new DefaultComboBoxModel<>(); 127 Map<String, UserInfo> info = UserIdentityManager.getInstance().getAllUserInformation(); 128 info.forEach((userName, userInfo) -> model.addElement(userName)); 129 JComboBox<String> rBox = new JComboBox<>(model); 130 UserInfo user = UserIdentityManager.getInstance().getUserInfo(); 131 String userName = user.getDisplayName() != null ? user.getDisplayName() : tr("Please login"); 132 if (model.getIndexOf(userName) < 0) model.addElement(userName); 133 model.setSelectedItem(userName); 134 rBox.addItemListener(new ItemListener() { 135 @Override 136 public void itemStateChanged(ItemEvent e) { 137 if (e.getStateChange() == ItemEvent.SELECTED) { 138 Logging.info("{0} was selected, switching to {1}", userName, e.getItem()); 139 model.setSelectedItem(e.getItem()); 140 } 141 } 142 }); 143 return rBox; 144 } 145 117 146 protected void build() { 118 147 jepMessage = new JMultilineLabel(""); 119 148 jepMessage.addHyperlinkListener(this); … … 128 157 JPanel pnl = new JPanel(new BorderLayout()); 129 158 pnl.add(lblWarning, BorderLayout.NORTH); 130 159 add(pnl, BorderLayout.WEST); 160 JComboBox<String> options = buildPossibleUserBox(); 161 if (options.getItemCount() > 1) add(buildPossibleUserBox(), BorderLayout.SOUTH); 131 162 } 132 163 133 164 public void setConfigurationParameterRequestListener(ConfigurationParameterRequestHandler handler) { -
src/org/openstreetmap/josm/gui/preferences/server/AuthenticationPreferencesPanel.java
7 7 import java.awt.GridBagConstraints; 8 8 import java.awt.GridBagLayout; 9 9 import java.awt.Insets; 10 import java.awt.event.ItemEvent; 11 import java.awt.event.ItemListener; 10 import java.awt.event.ActionEvent; 12 11 import java.beans.PropertyChangeEvent; 13 12 import java.beans.PropertyChangeListener; 13 import java.util.ArrayList; 14 import java.util.List; 15 import java.util.Map; 14 16 17 import javax.swing.AbstractAction; 15 18 import javax.swing.ButtonGroup; 19 import javax.swing.JButton; 16 20 import javax.swing.JPanel; 17 import javax.swing.JRadioButton;18 21 import javax.swing.JSeparator; 19 22 20 import org.openstreetmap.josm.data. oauth.OAuthAccessTokenHolder;23 import org.openstreetmap.josm.data.UserIdentityManager; 21 24 import org.openstreetmap.josm.gui.help.HelpUtil; 22 25 import org.openstreetmap.josm.gui.widgets.VerticallyScrollablePanel; 23 26 import org.openstreetmap.josm.io.OsmApi; 24 import org.openstreetmap.josm.io.auth.CredentialsManager;25 27 import org.openstreetmap.josm.spi.preferences.Config; 26 28 import org.openstreetmap.josm.tools.Logging; 27 29 … … 31 33 */ 32 34 public class AuthenticationPreferencesPanel extends VerticallyScrollablePanel implements PropertyChangeListener { 33 35 34 /** indicates whether we use basic authentication*/35 private final J RadioButton rbBasicAuthentication = new JRadioButton();36 /** indicates whether we use OAuth as authentication scheme*/37 private final J RadioButton rbOAuth = new JRadioButton();36 /** add a basic authentication method */ 37 private final JButton rbBasicAuthentication = new JButton(); 38 /** add a OAuth method */ 39 private final JButton rbOAuth = new JButton(); 38 40 /** the panel which contains the authentication parameters for the respective authentication scheme */ 39 41 private final JPanel pnlAuthenticationParameteters = new JPanel(new BorderLayout()); 40 /** the panel for the basic authentication parameters */41 private BasicAuthenticationPreferencesPanelpnlBasicAuthPreferences;42 /** the panel for the OAuth authentication parameters */43 private OAuthAuthenticationPreferencesPanelpnlOAuthPreferences;42 /** the panels for the basic authentication parameters */ 43 private List<BasicAuthenticationPreferencesPanel> pnlBasicAuthPreferences; 44 /** the panels for the OAuth authentication parameters */ 45 private List<OAuthAuthenticationPreferencesPanel> pnlOAuthPreferences; 44 46 /** the panel for messages notifier preferences */ 45 47 private FeaturesPanel pnlFeaturesPreferences; 46 48 … … 60 62 setLayout(new GridBagLayout()); 61 63 GridBagConstraints gc = new GridBagConstraints(); 62 64 63 AuthenticationMethodChangeListener authChangeListener = new AuthenticationMethodChangeListener(); 65 //-- the panel for API feature preferences 66 int tGridy = gc.gridy; 67 gc.gridy = 3; 68 gc.fill = GridBagConstraints.NONE; 69 pnlFeaturesPreferences = new FeaturesPanel(); 70 add(pnlFeaturesPreferences, gc); 71 gc.gridy = tGridy; 64 72 65 73 // -- radio button for basic authentication 66 74 gc.anchor = GridBagConstraints.NORTHWEST; … … 69 77 gc.weightx = 1.0; 70 78 gc.insets = new Insets(0, 0, 0, 3); 71 79 add(rbBasicAuthentication, gc); 72 rbBasicAuthentication.setText(tr("Use Basic Authentication")); 73 rbBasicAuthentication.setToolTipText(tr("Select to use HTTP basic authentication with your OSM username and password")); 74 rbBasicAuthentication.addItemListener(authChangeListener); 80 rbBasicAuthentication.setText(tr("Add Basic Authentication")); 81 rbBasicAuthentication.setToolTipText(tr("Select to add HTTP basic authentication with your OSM username and password")); 82 rbBasicAuthentication.setAction(new AbstractAction() { 83 @Override 84 public void actionPerformed(ActionEvent e) { 85 BasicAuthenticationPreferencesPanel panel = new BasicAuthenticationPreferencesPanel(); 86 panel.initFromPreferences(); 87 pnlBasicAuthPreferences.add(panel); 88 pnlAuthenticationParameteters.add(panel, BorderLayout.CENTER); 89 repaint(); 90 } 91 }); 75 92 76 93 //-- radio button for OAuth 77 94 gc.gridx = 0; 78 95 gc.weightx = 0.0; 79 96 add(rbOAuth, gc); 80 rbOAuth.setText(tr("Use OAuth")); 81 rbOAuth.setToolTipText(tr("Select to use OAuth as authentication mechanism")); 82 rbOAuth.addItemListener(authChangeListener); 97 rbOAuth.setText(tr("Add OAuth")); 98 rbOAuth.setToolTipText(tr("Select to add a OAuth authentication mechanism")); 99 rbOAuth.setAction(new AbstractAction() { 100 @Override 101 public void actionPerformed(ActionEvent e) { 102 OAuthAuthenticationPreferencesPanel panel = new OAuthAuthenticationPreferencesPanel(); 103 panel.initFromPreferences(); 104 pnlOAuthPreferences.add(panel); 105 pnlAuthenticationParameteters.add(panel, BorderLayout.CENTER); 106 repaint(); 107 } 108 }); 83 109 84 110 //-- radio button for OAuth 85 111 ButtonGroup bg = new ButtonGroup(); … … 96 122 add(pnlAuthenticationParameteters, gc); 97 123 98 124 //-- the two panels for authentication parameters 99 pnlBasicAuthPreferences = new BasicAuthenticationPreferencesPanel();100 pnlOAuthPreferences = new OAuthAuthenticationPreferencesPanel();125 pnlBasicAuthPreferences = new ArrayList<>(); 126 pnlOAuthPreferences = new ArrayList<>(); 101 127 102 rbBasicAuthentication.setSelected(true); 103 pnlAuthenticationParameteters.add(pnlBasicAuthPreferences, BorderLayout.CENTER); 128 populateAuthPanels(); 104 129 105 130 gc.gridy = 2; 106 131 add(new JSeparator(), gc); 132 } 107 133 108 //-- the panel for API feature preferences 109 gc.gridy = 3; 110 gc.fill = GridBagConstraints.NONE; 111 pnlFeaturesPreferences = new FeaturesPanel(); 112 add(pnlFeaturesPreferences, gc); 134 private void populateAuthPanels() { 135 List<Map<String, String>> users = UserIdentityManager.getInstance().getUserAuthInformation(); 136 for (Map<String, String> user : users) { 137 if ("oauth".equals(user.get("auth-type"))) { 138 OAuthAuthenticationPreferencesPanel panel = new OAuthAuthenticationPreferencesPanel(); 139 panel.initFromMap(user); 140 pnlOAuthPreferences.add(panel); 141 pnlAuthenticationParameteters.add(panel); 142 } else if ("basic".equals(user.get("auth-type"))) { 143 BasicAuthenticationPreferencesPanel panel = new BasicAuthenticationPreferencesPanel(); 144 panel.initFromMap(user); 145 pnlBasicAuthPreferences.add(panel); 146 pnlAuthenticationParameteters.add(panel); 147 } 148 } 149 repaint(); 113 150 } 114 151 115 152 /** … … 126 163 "osm-server.auth-method", authMethod)); 127 164 rbBasicAuthentication.setSelected(true); 128 165 } 129 pnlBasicAuthPreferences.initFromPreferences(); 130 pnlOAuthPreferences.initFromPreferences(); 166 List<Map<String, String>> users = UserIdentityManager.getInstance().getUserAuthInformation(); 167 for (Map<String, String> user : users) { 168 if ("oauth".equals(user.get("auth-type"))) { 169 OAuthAuthenticationPreferencesPanel panel = new OAuthAuthenticationPreferencesPanel(); 170 panel.initFromMap(user); 171 pnlOAuthPreferences.add(panel); 172 } else if ("basic".equals(user.get("auth-type"))) { 173 BasicAuthenticationPreferencesPanel panel = new BasicAuthenticationPreferencesPanel(); 174 panel.initFromMap(user); 175 pnlBasicAuthPreferences.add(panel); 176 } 177 } 131 178 pnlFeaturesPreferences.initFromPreferences(); 132 179 } 133 180 … … 143 190 authMethod = "oauth"; 144 191 } 145 192 Config.getPref().put("osm-server.auth-method", authMethod); 146 if ("basic".equals(authMethod)) { 147 // save username and password and clear the OAuth token 148 pnlBasicAuthPreferences.saveToPreferences(); 149 OAuthAccessTokenHolder.getInstance().clear(); 150 OAuthAccessTokenHolder.getInstance().save(CredentialsManager.getInstance()); 151 } else if ("oauth".equals(authMethod)) { 152 // clear the password in the preferences 153 pnlBasicAuthPreferences.clearPassword(); 154 pnlBasicAuthPreferences.saveToPreferences(); 155 pnlOAuthPreferences.saveToPreferences(); 193 for (BasicAuthenticationPreferencesPanel panel : pnlBasicAuthPreferences) { 194 panel.saveToPreferences(); 156 195 } 196 for (OAuthAuthenticationPreferencesPanel panel : pnlOAuthPreferences) { 197 panel.saveToPreferences(); 198 } 157 199 // save message notifications preferences. To be done after authentication preferences. 158 200 pnlFeaturesPreferences.saveToPreferences(); 159 201 } 160 202 161 /**162 * Listens to changes in the authentication method163 */164 class AuthenticationMethodChangeListener implements ItemListener {165 @Override166 public void itemStateChanged(ItemEvent e) {167 if (rbBasicAuthentication.isSelected()) {168 pnlAuthenticationParameteters.removeAll();169 pnlAuthenticationParameteters.add(pnlBasicAuthPreferences, BorderLayout.CENTER);170 pnlBasicAuthPreferences.revalidate();171 } else {172 pnlAuthenticationParameteters.removeAll();173 pnlAuthenticationParameteters.add(pnlOAuthPreferences, BorderLayout.CENTER);174 pnlOAuthPreferences.revalidate();175 }176 repaint();177 }178 }179 180 203 @Override 181 204 public void propertyChange(PropertyChangeEvent evt) { 182 if (pnlOAuthPreferences != null) { 183 pnlOAuthPreferences.propertyChange(evt); 205 /** TODO is this still necessary? */ 206 if (pnlOAuthPreferences != null && !pnlOAuthPreferences.isEmpty()) { 207 for (OAuthAuthenticationPreferencesPanel panel : pnlOAuthPreferences) { 208 panel.propertyChange(evt); 209 } 184 210 } 185 211 } 186 212 } -
src/org/openstreetmap/josm/gui/preferences/server/BasicAuthenticationPreferencesPanel.java
9 9 import java.awt.Insets; 10 10 import java.net.Authenticator.RequestorType; 11 11 import java.net.PasswordAuthentication; 12 import java.util.List; 13 import java.util.Map; 14 import java.util.TreeMap; 12 15 13 16 import javax.swing.BorderFactory; 14 17 import javax.swing.JLabel; 15 18 import javax.swing.JPanel; 16 19 20 import org.openstreetmap.josm.data.UserIdentityManager; 17 21 import org.openstreetmap.josm.gui.widgets.JosmPasswordField; 18 22 import org.openstreetmap.josm.gui.widgets.JosmTextField; 19 23 import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator; … … 93 97 * Inits contents from preferences. 94 98 */ 95 99 public void initFromPreferences() { 96 CredentialsAgent cm = CredentialsManager.getInstance(); 97 try { 98 decorationPanel.removeAll(); 99 decorationPanel.add(cm.getPreferencesDecorationPanel(), BorderLayout.CENTER); 100 PasswordAuthentication pa = cm.lookup(RequestorType.SERVER, OsmApi.getOsmApi().getHost()); 101 if (pa == null) { 102 tfOsmUserName.setText(""); 103 tfOsmPassword.setText(""); 104 } else { 105 tfOsmUserName.setText(pa.getUserName() == null ? "" : pa.getUserName()); 106 tfOsmPassword.setText(pa.getPassword() == null ? "" : String.valueOf(pa.getPassword())); 100 initFromMap(null); 101 } 102 103 /** 104 * Initializes contents from a map 105 * @param user The map with the login/password 106 */ 107 public void initFromMap(Map<String, String> user) { 108 if (user == null) { 109 user = new TreeMap<>(); 110 CredentialsAgent cm = CredentialsManager.getInstance(); 111 try { 112 decorationPanel.removeAll(); 113 decorationPanel.add(cm.getPreferencesDecorationPanel(), BorderLayout.CENTER); 114 PasswordAuthentication pa = cm.lookup(RequestorType.SERVER, OsmApi.getOsmApi().getHost()); 115 if (pa == null) { 116 user.put("login", ""); 117 user.put("password", ""); 118 } else { 119 user.put("login", pa.getUserName() == null ? "" : pa.getUserName()); 120 user.put("password", pa.getPassword() == null ? "" : String.valueOf(pa.getPassword())); 121 } 122 } catch (CredentialsAgentException e) { 123 Logging.error(e); 124 Logging.warn(tr("Failed to retrieve OSM credentials from credential manager.")); 125 Logging.warn(tr("Current credential manager is of type ''{0}''", cm.getClass().getName())); 126 user.put("login", ""); 127 user.put("password", ""); 107 128 } 108 } catch (CredentialsAgentException e) {109 Logging.error(e);110 Logging.warn(tr("Failed to retrieve OSM credentials from credential manager."));111 Logging.warn(tr("Current credential manager is of type ''{0}''", cm.getClass().getName()));112 tfOsmUserName.setText("");113 tfOsmPassword.setText("");114 129 } 130 131 tfOsmUserName.setText(user.get("login") != null ? user.get("login") : ""); 132 tfOsmPassword.setText(user.get("password") != null ? user.get("password") : ""); 115 133 } 116 134 117 135 /** … … 130 148 Logging.warn(tr("Failed to save OSM credentials to credential manager.")); 131 149 Logging.warn(tr("Current credential manager is of type ''{0}''", cm.getClass().getName())); 132 150 } 151 List<Map<String, String>> users = UserIdentityManager.getInstance().getUserAuthInformation(); 152 boolean present = false; 153 for (Map<String, String> user : users) { 154 if ("basic".equals(user.get("auth-type"))) { 155 if (tfOsmUserName.getText().trim().equals(user.get("login"))) { 156 user.put("password", tfOsmPassword.getPassword().toString()); 157 user.put("url", OsmApi.getOsmApi().getHost()); 158 present = true; 159 break; 160 } 161 } 162 } 163 if (!present) { 164 Map<String, String> map = new TreeMap<>(); 165 map.put("login", tfOsmUserName.getText().trim()); 166 map.put("password", tfOsmPassword.getParent().toString()); 167 map.put("url", OsmApi.getOsmApi().getHost()); 168 } 133 169 } 134 170 135 171 /** -
src/org/openstreetmap/josm/gui/preferences/server/OAuthAuthenticationPreferencesPanel.java
14 14 import java.awt.event.ItemEvent; 15 15 import java.beans.PropertyChangeEvent; 16 16 import java.beans.PropertyChangeListener; 17 import java.util.Map; 18 import java.util.TreeMap; 17 19 18 20 import javax.swing.AbstractAction; 19 21 import javax.swing.BorderFactory; … … 51 53 private final JPanel pnlAuthorisationMessage = new JPanel(new BorderLayout()); 52 54 private final NotYetAuthorisedPanel pnlNotYetAuthorised = new NotYetAuthorisedPanel(); 53 55 private final AdvancedOAuthPropertiesPanel pnlAdvancedProperties = new AdvancedOAuthPropertiesPanel(); 54 private final AlreadyAuthorisedPanel pnlAlreadyAuthorised = new AlreadyAuthorisedPanel( );56 private final AlreadyAuthorisedPanel pnlAlreadyAuthorised = new AlreadyAuthorisedPanel(null); 55 57 private String apiUrl; 56 58 57 59 /** … … 125 127 } 126 128 127 129 protected void refreshView() { 130 Map<String, String> map = new TreeMap<>(); 131 if (OAuthAccessTokenHolder.getInstance().containsAccessToken()) { 132 map.put("login", OAuthAccessTokenHolder.getInstance().getAccessTokenKey()); 133 map.put("password", OAuthAccessTokenHolder.getInstance().getAccessTokenSecret()); 134 } 135 refreshView(map); 136 } 137 138 protected void refreshView(Map<String, String> user) { 128 139 pnlAuthorisationMessage.removeAll(); 129 if ( OAuthAccessTokenHolder.getInstance().containsAccessToken()) {140 if (user.containsKey("login") && user.containsKey("password")) { 130 141 pnlAuthorisationMessage.add(pnlAlreadyAuthorised, BorderLayout.CENTER); 131 pnlAlreadyAuthorised.refreshView( );142 pnlAlreadyAuthorised.refreshView(user); 132 143 pnlAlreadyAuthorised.revalidate(); 133 144 } else { 134 145 pnlAuthorisationMessage.add(pnlNotYetAuthorised, BorderLayout.CENTER); … … 156 167 } 157 168 158 169 /** 170 * Initializes the panel from a map 171 * @param user The map with a {@code login} and {@code password}. 172 * Optional information includes {@code url}. 173 */ 174 public void initFromMap(Map<String, String> user) { 175 if (user.containsKey("url")) { 176 setApiUrl(user.get("url").trim()); 177 } else { 178 setApiUrl(OsmApi.getOsmApi().getServerUrl().trim()); 179 } 180 refreshView(user); 181 } 182 183 /** 159 184 * Saves the current values to preferences 160 185 */ 161 186 public void saveToPreferences() { … … 215 240 private final JosmTextField tfAccessTokenSecret = new JosmTextField(); 216 241 217 242 /** 218 * Constructs a new {@code AlreadyAuthorisedPanel}. 243 * Constructs a new {@code AlreadyAUthorisedPanel}. 244 * @param map The map with the authentication information 219 245 */ 220 AlreadyAuthorisedPanel() { 246 AlreadyAuthorisedPanel(Map<String, String> map) { 247 if (map == null) { 248 map = new TreeMap<>(); 249 map.put("login", OAuthAccessTokenHolder.getInstance().getAccessTokenKey()); 250 map.put("password", OAuthAccessTokenHolder.getInstance().getAccessTokenSecret()); 251 } 252 tfAccessTokenKey.setText(map.get("login")); 253 tfAccessTokenSecret.setText(map.get("password")); 221 254 build(); 222 refreshView( );255 refreshView(map); 223 256 } 224 257 225 258 protected void build() { … … 291 324 add(new JPanel(), gc); 292 325 } 293 326 294 protected final void refreshView( ) {295 String v = OAuthAccessTokenHolder.getInstance().getAccessTokenKey();327 protected final void refreshView(Map<String, String> user) { 328 String v = user.get("login"); 296 329 tfAccessTokenKey.setText(v == null ? "" : v); 297 v = OAuthAccessTokenHolder.getInstance().getAccessTokenSecret();330 v = user.get("password"); 298 331 tfAccessTokenSecret.setText(v == null ? "" : v); 299 332 cbSaveToPreferences.setSelected(OAuthAccessTokenHolder.getInstance().isSaveToPreferences()); 300 333 } -
src/org/openstreetmap/josm/io/OsmConnection.java
104 104 * Adds an authentication header for basic authentication 105 105 * 106 106 * @param con the connection 107 * @ throws OsmTransferException if something went wrong. Check for nested exceptions107 * @param response the response with username/password information 108 108 */ 109 protected void addBasicAuthorizationHeader(HttpClient con) throws OsmTransferException { 110 CredentialsAgentResponse response; 111 try { 112 synchronized (CredentialsManager.getInstance()) { 113 response = CredentialsManager.getInstance().getCredentials(RequestorType.SERVER, 114 con.getURL().getHost(), false /* don't know yet whether the credentials will succeed */); 115 } 116 } catch (CredentialsAgentException e) { 117 throw new OsmTransferException(e); 118 } 109 protected void addBasicAuthorizationHeader(HttpClient con, CredentialsAgentResponse response) { 119 110 if (response != null) { 120 111 if (response.isCanceled()) { 121 112 cancel = true; … … 132 123 * Signs the connection with an OAuth authentication header 133 124 * 134 125 * @param connection the connection 126 * @param holder specific OAuth access token 135 127 * 136 128 * @throws MissingOAuthAccessTokenException if there is currently no OAuth Access Token configured 137 129 * @throws OsmTransferException if signing fails 138 130 */ 139 protected void addOAuthAuthorizationHeader(HttpClient connection ) throws OsmTransferException {131 protected void addOAuthAuthorizationHeader(HttpClient connection, OAuthAccessTokenHolder holder) throws OsmTransferException { 140 132 if (oauthParameters == null) { 141 133 oauthParameters = OAuthParameters.createFromApiUrl(OsmApi.getOsmApi().getServerUrl()); 142 134 } 143 135 OAuthConsumer consumer = oauthParameters.buildConsumer(); 144 OAuthAccessTokenHolder holder = OAuthAccessTokenHolder.getInstance();145 136 if (!holder.containsAccessToken()) { 146 137 obtainAccessToken(connection); 147 138 } … … 177 168 } 178 169 179 170 protected void addAuth(HttpClient connection) throws OsmTransferException { 180 final String authMethod = OsmApi.getAuthMethod(); 181 if ("basic".equals(authMethod)) { 182 addBasicAuthorizationHeader(connection); 183 } else if ("oauth".equals(authMethod)) { 184 addOAuthAuthorizationHeader(connection); 171 addAuth(connection, null); 172 } 173 174 /** 175 * Add authorization information to a connection 176 * @param connection to add authorization information to 177 * @param holder A {@code CredentialsAgentResponse} for basic authorization, 178 * {@code OAuthAccessTokenHolder} for OAuth, or {@code null} for defaults. 179 * @throws OsmTransferException if the authorization is not valid 180 */ 181 protected void addAuth(HttpClient connection, Object holder) throws OsmTransferException{ 182 if (holder == null) { 183 final String authMethod = OsmApi.getAuthMethod(); 184 if ("basic".equals(authMethod)) { 185 CredentialsAgentResponse response; 186 try { 187 synchronized (CredentialsManager.getInstance()) { 188 response = CredentialsManager.getInstance().getCredentials(RequestorType.SERVER, 189 connection.getURL().getHost(), false /* don't know yet whether the credentials will succeed */); 190 } 191 } catch (CredentialsAgentException e) { 192 throw new OsmTransferException(e); 193 } 194 holder = response; 195 } else if ("oauth".equals(authMethod)) { 196 holder = OAuthAccessTokenHolder.getInstance(); 197 } else { 198 String msg = tr("Unexpected value for preference ''{0}''. Got ''{1}''.", "osm-server.auth-method", authMethod); 199 Logging.warn(msg); 200 throw new OsmTransferException(msg); 201 } 202 } 203 204 if (holder instanceof OAuthAccessTokenHolder) { 205 addOAuthAuthorizationHeader(connection, (OAuthAccessTokenHolder) holder); 206 } else if (holder instanceof CredentialsAgentResponse) { 207 addBasicAuthorizationHeader(connection, (CredentialsAgentResponse) holder); 185 208 } else { 186 String msg = tr("Unexpected value for preference ''{0}''. Got ''{1}''.", "osm-server.auth-method", authMethod);209 String msg = tr("Unexpected object for authorizations. Got ''{0}''.", holder.getClass().getName()); 187 210 Logging.warn(msg); 188 211 throw new OsmTransferException(msg); 189 212 } -
src/org/openstreetmap/josm/io/OsmServerReader.java
79 79 * @throws OsmTransferException if data transfer errors occur 80 80 */ 81 81 protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor, String reason) throws OsmTransferException { 82 return getInputStream(urlStr, progressMonitor, reason, null); 83 } 84 85 /** 86 * Open a connection to the given url and return a reader on the input stream 87 * from that connection. In case of user cancel, return <code>null</code>. 88 * Relative URL's are directed to API base URL. 89 * @param urlStr The url to connect to. 90 * @param progressMonitor progress monitoring and abort handler 91 * @param reason The reason to show on console. Can be {@code null} if no reason is given 92 * @param authentication A {@code CredentialsAgentResponse} for basic authorization, 93 * {@code OAuthAccessTokenHolder} for OAuth, or {@code null} for defaults. 94 * @return A reader reading the input stream (servers answer) or <code>null</code>. 95 * @throws OsmTransferException if data transfer errors occur 96 */ 97 protected InputStream getInputStream(String urlStr, ProgressMonitor progressMonitor, String reason, Object authentication) throws OsmTransferException { 82 98 try { 83 99 api.initialize(progressMonitor); 84 100 String url = urlStr.startsWith("http") ? urlStr : (getBaseUrl() + urlStr); 85 return getInputStreamRaw(url, progressMonitor, reason );101 return getInputStreamRaw(url, progressMonitor, reason, authentication); 86 102 } finally { 87 103 progressMonitor.invalidate(); 88 104 } … … 122 138 } 123 139 124 140 /** 141 * Open a connection to the given url and return a reader on the input stream 142 * from that connection. In case of user cancel, return <code>null</code>. 143 * @param urlStr The exact url to connect to. 144 * @param progressMonitor progress monitoring and abort handler 145 * @param reason The reason to show on console. Can be {@code null} if no reason is given 146 * @return An reader reading the input stream (servers answer) or <code>null</code>. 147 * @throws OsmTransferException if data transfer errors occur 148 * @since xxx 149 */ 150 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason, Object auth) throws OsmTransferException { 151 return getInputStreamRaw(urlStr, progressMonitor, reason, false, "GET", null, auth); 152 } 153 154 /** 125 155 * Open a connection to the given url (if HTTP, trough a GET request) and return a reader on the input stream 126 156 * from that connection. In case of user cancel, return <code>null</code>. 127 157 * @param urlStr The exact url to connect to. … … 151 181 * @throws OsmTransferException if data transfer errors occur 152 182 * @since 12596 153 183 */ 184 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason, 185 boolean uncompressAccordingToContentDisposition, String httpMethod, byte[] requestBody) throws OsmTransferException { 186 return getInputStreamRaw(urlStr, progressMonitor, reason, uncompressAccordingToContentDisposition, httpMethod, requestBody, null); 187 } 188 189 /** 190 * Open a connection to the given url (if HTTP, with the specified method) and return a reader on the input stream 191 * from that connection. In case of user cancel, return <code>null</code>. 192 * @param urlStr The exact url to connect to. 193 * @param progressMonitor progress monitoring and abort handler 194 * @param reason The reason to show on console. Can be {@code null} if no reason is given 195 * @param uncompressAccordingToContentDisposition Whether to inspect the HTTP header {@code Content-Disposition} 196 * for {@code filename} and uncompress a gzip/bzip2/xz/zip stream. 197 * @param httpMethod HTTP method ("GET", "POST" or "PUT") 198 * @param requestBody HTTP request body (for "POST" and "PUT" methods only). Must be null for "GET" method. 199 * @param auth A {@code CredentialsAgentResponse} for basic authorization, 200 * {@code OAuthAccessTokenHolder} for OAuth, or {@code null} for defaults. 201 * @return An reader reading the input stream (servers answer) or {@code null}. 202 * @throws OsmTransferException if data transfer errors occur 203 * @since xxx 204 */ 154 205 @SuppressWarnings("resource") 155 206 protected InputStream getInputStreamRaw(String urlStr, ProgressMonitor progressMonitor, String reason, 156 boolean uncompressAccordingToContentDisposition, String httpMethod, byte[] requestBody) throws OsmTransferException { 207 boolean uncompressAccordingToContentDisposition, String httpMethod, byte[] requestBody, 208 Object auth) throws OsmTransferException { 157 209 try { 158 210 OnlineResource.JOSM_WEBSITE.checkOfflineAccess(urlStr, Config.getUrls().getJOSMWebsite()); 159 211 OnlineResource.OSM_API.checkOfflineAccess(urlStr, OsmApi.getOsmApi().getServerUrl()); … … 182 234 activeConnection = client; 183 235 adaptRequest(client); 184 236 if (doAuthenticate) { 185 addAuth(client );237 addAuth(client, auth); 186 238 } 187 239 if (cancel) 188 240 throw new OsmTransferCanceledException("Operation canceled"); … … 415 467 */ 416 468 public <T> T fetchData(String api, String subtask, DomParser<T> parser, ProgressMonitor monitor, String reason) 417 469 throws OsmTransferException { 470 return fetchData(api, subtask, parser, monitor, reason, null); 471 } 472 473 /** 474 * Fetches generic data from the DOM document resulting an API call. 475 * @param api the OSM API call 476 * @param subtask the subtask translated message 477 * @param parser the parser converting the DOM document (OSM API result) 478 * @param <T> data type 479 * @param monitor The progress monitor 480 * @param reason The reason to show on console. Can be {@code null} if no reason is given 481 * @param authentication A {@code CredentialsAgentResponse} for basic authorization, 482 * {@code OAuthAccessTokenHolder} for OAuth, or {@code null} for defaults. 483 * @return The converted data 484 * @throws OsmTransferException if something goes wrong 485 * @since 12510 486 */ 487 public <T> T fetchData(String api, String subtask, DomParser<T> parser, ProgressMonitor monitor, String reason, Object authentication) 488 throws OsmTransferException { 418 489 try { 419 490 monitor.beginTask(""); 420 491 monitor.indeterminateSubTask(subtask); 421 try (InputStream in = getInputStream(api, monitor.createSubTaskMonitor(1, true), reason )) {492 try (InputStream in = getInputStream(api, monitor.createSubTaskMonitor(1, true), reason, authentication)) { 422 493 return parser.parse(XmlUtils.parseSafeDOM(in)); 423 494 } 424 495 } catch (OsmTransferException e) { -
src/org/openstreetmap/josm/io/OsmServerUserInfoReader.java
13 13 import javax.xml.xpath.XPathFactory; 14 14 15 15 import org.openstreetmap.josm.data.coor.LatLon; 16 import org.openstreetmap.josm.data.oauth.OAuthAccessTokenHolder; 16 17 import org.openstreetmap.josm.data.osm.DataSet; 17 18 import org.openstreetmap.josm.data.osm.UserInfo; 18 19 import org.openstreetmap.josm.gui.progress.ProgressMonitor; 20 import org.openstreetmap.josm.io.auth.CredentialsAgentResponse; 21 import org.openstreetmap.josm.tools.Logging; 19 22 import org.openstreetmap.josm.tools.UncheckedParseException; 20 23 import org.openstreetmap.josm.tools.XmlParsingException; 21 24 import org.openstreetmap.josm.tools.date.DateUtils; … … 159 162 } 160 163 161 164 /** 165 * Fetches user info without explicit reason with a specific authentication 166 * @param monitor The progress monitor 167 * @param authentication The authentication object ({@code OAuthAccessTokenHolder} 168 * or {@code CredentialsAgentResponse}) 169 * @return The user info 170 * @throws OsmTransferException if something goes wrong 171 * @since xxx 172 */ 173 public UserInfo fetchUserInfo(ProgressMonitor monitor, Object authentication) throws OsmTransferException { 174 if (authentication instanceof String) { 175 return fetchUserInfo(monitor, null, (String) authentication); 176 } else { 177 return fetchUserInfo(monitor, authentication, null); 178 } 179 } 180 181 /** 162 182 * Fetches user info, with an explicit reason. 163 183 * @param monitor The progress monitor 164 184 * @param reason The reason to show on console. Can be {@code null} if no reason is given … … 167 187 * @since 6695 168 188 */ 169 189 public UserInfo fetchUserInfo(ProgressMonitor monitor, String reason) throws OsmTransferException { 170 return fetchData("user/details", tr("Reading user info ..."), 171 OsmServerUserInfoReader::buildFromXML, monitor, reason); 190 return fetchUserInfo(monitor, null, reason); 172 191 } 192 193 /** 194 * Fetches user info, with an explicit reason. 195 * @param monitor The progress monitor 196 * @param authentication A {@code CredentialsAgentResponse} for basic authorization, 197 * {@code OAuthAccessTokenHolder} for OAuth, or {@code null} for defaults. 198 * @param reason The reason to show on console. Can be {@code null} if no reason is given 199 * @return The user info 200 * @throws OsmTransferException if something goes wrong 201 * @since xxx 202 */ 203 public UserInfo fetchUserInfo(ProgressMonitor monitor, Object authentication , String reason) throws OsmTransferException { 204 if (authentication instanceof OAuthAccessTokenHolder || authentication instanceof CredentialsAgentResponse 205 || authentication == null) { 206 return fetchData("user/details", tr("Reading user info ..."), 207 OsmServerUserInfoReader::buildFromXML, monitor, reason, authentication); 208 } else { 209 String msg = tr("We did not get a valid authentication object ({0})", authentication.getClass().getName()); 210 Logging.warn(msg); 211 throw new OsmTransferException(msg); 212 } 213 } 173 214 }