source: josm/trunk/src/org/openstreetmap/josm/gui/preferences/server/OAuthAuthenticationPreferencesPanel.java@ 16422

Last change on this file since 16422 was 16422, checked in by simon04, 4 years ago

fix #18820, see #13872 - Make OAuth signing of all API requests configurable

  • Property svn:eol-style set to native
File size: 13.7 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.preferences.server;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.BorderLayout;
7import java.awt.Color;
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.ItemEvent;
15import java.beans.PropertyChangeEvent;
16import java.beans.PropertyChangeListener;
17
18import javax.swing.AbstractAction;
19import javax.swing.BorderFactory;
20import javax.swing.JButton;
21import javax.swing.JCheckBox;
22import javax.swing.JLabel;
23import javax.swing.JPanel;
24
25import org.openstreetmap.josm.data.oauth.OAuthAccessTokenHolder;
26import org.openstreetmap.josm.data.oauth.OAuthParameters;
27import org.openstreetmap.josm.data.oauth.OAuthToken;
28import org.openstreetmap.josm.gui.MainApplication;
29import org.openstreetmap.josm.gui.oauth.AdvancedOAuthPropertiesPanel;
30import org.openstreetmap.josm.gui.oauth.OAuthAuthorizationWizard;
31import org.openstreetmap.josm.gui.oauth.TestAccessTokenTask;
32import org.openstreetmap.josm.gui.widgets.JMultilineLabel;
33import org.openstreetmap.josm.gui.widgets.JosmTextField;
34import org.openstreetmap.josm.io.OsmApi;
35import org.openstreetmap.josm.io.auth.CredentialsManager;
36import org.openstreetmap.josm.tools.GBC;
37import org.openstreetmap.josm.tools.ImageProvider;
38import org.openstreetmap.josm.tools.Logging;
39import org.openstreetmap.josm.tools.UserCancelException;
40
41/**
42 * The preferences panel for the OAuth preferences. This just a summary panel
43 * showing the current Access Token Key and Access Token Secret, if the
44 * user already has an Access Token.
45 *
46 * For initial authorisation see {@link OAuthAuthorizationWizard}.
47 * @since 2745
48 */
49public class OAuthAuthenticationPreferencesPanel extends JPanel implements PropertyChangeListener {
50 private final JCheckBox cbUseForAllRequests = new JCheckBox();
51 private final JCheckBox cbShowAdvancedParameters = new JCheckBox(tr("Display Advanced OAuth Parameters"));
52 private final JCheckBox cbSaveToPreferences = new JCheckBox(tr("Save to preferences"));
53 private final JPanel pnlAuthorisationMessage = new JPanel(new BorderLayout());
54 private final NotYetAuthorisedPanel pnlNotYetAuthorised = new NotYetAuthorisedPanel();
55 private final AdvancedOAuthPropertiesPanel pnlAdvancedProperties = new AdvancedOAuthPropertiesPanel();
56 private final AlreadyAuthorisedPanel pnlAlreadyAuthorised = new AlreadyAuthorisedPanel();
57 private String apiUrl;
58
59 /**
60 * Create the panel
61 */
62 public OAuthAuthenticationPreferencesPanel() {
63 build();
64 refreshView();
65 }
66
67 /**
68 * Builds the panel for entering the advanced OAuth parameters
69 *
70 * @return panel with advanced settings
71 */
72 protected JPanel buildAdvancedPropertiesPanel() {
73 JPanel pnl = new JPanel(new GridBagLayout());
74
75 cbUseForAllRequests.setText(tr("Use OAuth for all requests to {0}", OsmApi.getOsmApi().getServerUrl()));
76 cbUseForAllRequests.setToolTipText(tr("For user-based bandwith limit instead of IP-based one"));
77 pnl.add(cbUseForAllRequests, GBC.eol().fill(GBC.HORIZONTAL));
78
79 pnl.add(cbShowAdvancedParameters, GBC.eol().fill(GBC.HORIZONTAL));
80 cbShowAdvancedParameters.setSelected(false);
81 cbShowAdvancedParameters.addItemListener(
82 evt -> pnlAdvancedProperties.setVisible(evt.getStateChange() == ItemEvent.SELECTED)
83 );
84
85 pnl.add(pnlAdvancedProperties, GBC.eol().fill(GBC.HORIZONTAL).insets(0, 3, 0, 0));
86 pnlAdvancedProperties.initialize(OsmApi.getOsmApi().getServerUrl());
87 pnlAdvancedProperties.setBorder(
88 BorderFactory.createCompoundBorder(
89 BorderFactory.createLineBorder(Color.GRAY, 1),
90 BorderFactory.createEmptyBorder(3, 3, 3, 3)
91 )
92 );
93 pnlAdvancedProperties.setVisible(false);
94 return pnl;
95 }
96
97 /**
98 * builds the UI
99 */
100 protected final void build() {
101 setLayout(new GridBagLayout());
102 setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
103 GridBagConstraints gc = new GridBagConstraints();
104
105 // the panel for the OAuth parameters. pnlAuthorisationMessage is an
106 // empty panel. It is going to be filled later, depending on the
107 // current OAuth state in JOSM.
108 gc.fill = GridBagConstraints.BOTH;
109 gc.anchor = GridBagConstraints.NORTHWEST;
110 gc.weighty = 1.0;
111 gc.weightx = 1.0;
112 gc.insets = new Insets(10, 0, 0, 0);
113 add(pnlAuthorisationMessage, gc);
114 }
115
116 protected void refreshView() {
117 pnlAuthorisationMessage.removeAll();
118 if (OAuthAccessTokenHolder.getInstance().containsAccessToken()) {
119 pnlAuthorisationMessage.add(pnlAlreadyAuthorised, BorderLayout.CENTER);
120 pnlAlreadyAuthorised.refreshView();
121 pnlAlreadyAuthorised.revalidate();
122 } else {
123 pnlAuthorisationMessage.add(pnlNotYetAuthorised, BorderLayout.CENTER);
124 pnlNotYetAuthorised.revalidate();
125 }
126 repaint();
127 }
128
129 /**
130 * Sets the URL of the OSM API for which this panel is currently displaying OAuth properties.
131 *
132 * @param apiUrl the api URL
133 */
134 public void setApiUrl(String apiUrl) {
135 this.apiUrl = apiUrl;
136 pnlAdvancedProperties.setApiUrl(apiUrl);
137 }
138
139 /**
140 * Initializes the panel from preferences
141 */
142 public void initFromPreferences() {
143 setApiUrl(OsmApi.getOsmApi().getServerUrl().trim());
144 cbUseForAllRequests.setSelected(OsmApi.USE_OAUTH_FOR_ALL_REQUESTS.get());
145 refreshView();
146 }
147
148 /**
149 * Saves the current values to preferences
150 */
151 public void saveToPreferences() {
152 OAuthAccessTokenHolder.getInstance().setSaveToPreferences(cbSaveToPreferences.isSelected());
153 OAuthAccessTokenHolder.getInstance().save(CredentialsManager.getInstance());
154 OsmApi.USE_OAUTH_FOR_ALL_REQUESTS.put(cbUseForAllRequests.isSelected());
155 pnlAdvancedProperties.rememberPreferences();
156 }
157
158 /**
159 * The preferences panel displayed if there is currently no Access Token available.
160 * This means that the user didn't run through the OAuth authorisation procedure yet.
161 *
162 */
163 private class NotYetAuthorisedPanel extends JPanel {
164 /**
165 * Constructs a new {@code NotYetAuthorisedPanel}.
166 */
167 NotYetAuthorisedPanel() {
168 build();
169 }
170
171 protected void build() {
172 setLayout(new GridBagLayout());
173 GridBagConstraints gc = new GridBagConstraints();
174
175 // A message explaining that the user isn't authorised yet
176 gc.anchor = GridBagConstraints.NORTHWEST;
177 gc.insets = new Insets(0, 0, 3, 0);
178 gc.fill = GridBagConstraints.HORIZONTAL;
179 gc.weightx = 1.0;
180 JMultilineLabel lbl = new JMultilineLabel(
181 tr("You do not have an Access Token yet to access the OSM server using OAuth. Please authorize first."));
182 add(lbl, gc);
183 lbl.setFont(lbl.getFont().deriveFont(Font.PLAIN));
184
185 // Action for authorising now
186 gc.gridy = 1;
187 gc.fill = GridBagConstraints.NONE;
188 gc.weightx = 0.0;
189 add(new JButton(new AuthoriseNowAction()), gc);
190
191 // filler - grab remaining space
192 gc.gridy = 2;
193 gc.fill = GridBagConstraints.BOTH;
194 gc.weightx = 1.0;
195 gc.weighty = 1.0;
196 add(new JPanel(), gc);
197 }
198 }
199
200 /**
201 * The preferences panel displayed if there is currently an AccessToken available.
202 *
203 */
204 private class AlreadyAuthorisedPanel extends JPanel {
205 private final JosmTextField tfAccessTokenKey = new JosmTextField(null, null, 0, false);
206 private final JosmTextField tfAccessTokenSecret = new JosmTextField(null, null, 0, false);
207
208 /**
209 * Constructs a new {@code AlreadyAuthorisedPanel}.
210 */
211 AlreadyAuthorisedPanel() {
212 build();
213 refreshView();
214 }
215
216 protected void build() {
217 setLayout(new GridBagLayout());
218 GridBagConstraints gc = new GridBagConstraints();
219 gc.anchor = GridBagConstraints.NORTHWEST;
220 gc.insets = new Insets(0, 0, 3, 3);
221 gc.fill = GridBagConstraints.HORIZONTAL;
222 gc.weightx = 1.0;
223 gc.gridwidth = 2;
224 JMultilineLabel lbl = new JMultilineLabel(tr("You already have an Access Token to access the OSM server using OAuth."));
225 add(lbl, gc);
226 lbl.setFont(lbl.getFont().deriveFont(Font.PLAIN));
227
228 // -- access token key
229 gc.gridy = 1;
230 gc.gridx = 0;
231 gc.gridwidth = 1;
232 gc.weightx = 0.0;
233 add(new JLabel(tr("Access Token Key:")), gc);
234
235 gc.gridx = 1;
236 gc.weightx = 1.0;
237 add(tfAccessTokenKey, gc);
238 tfAccessTokenKey.setEditable(false);
239
240 // -- access token secret
241 gc.gridy = 2;
242 gc.gridx = 0;
243 gc.gridwidth = 1;
244 gc.weightx = 0.0;
245 add(new JLabel(tr("Access Token Secret:")), gc);
246
247 gc.gridx = 1;
248 gc.weightx = 1.0;
249 add(tfAccessTokenSecret, gc);
250 tfAccessTokenSecret.setEditable(false);
251
252 // -- access token secret
253 gc.gridy = 3;
254 gc.gridx = 0;
255 gc.gridwidth = 2;
256 gc.weightx = 1.0;
257 add(cbSaveToPreferences, gc);
258 cbSaveToPreferences.setSelected(OAuthAccessTokenHolder.getInstance().isSaveToPreferences());
259
260 // -- action buttons
261 JPanel btns = new JPanel(new FlowLayout(FlowLayout.LEFT));
262 btns.add(new JButton(new RenewAuthorisationAction()));
263 btns.add(new JButton(new TestAuthorisationAction()));
264 gc.gridy = 4;
265 gc.gridx = 0;
266 gc.gridwidth = 2;
267 gc.weightx = 1.0;
268 add(btns, gc);
269
270 // the panel with the advanced options
271 gc.gridy = 5;
272 gc.gridx = 0;
273 gc.gridwidth = 2;
274 gc.weightx = 1.0;
275 add(buildAdvancedPropertiesPanel(), gc);
276
277 // filler - grab the remaining space
278 gc.gridy = 6;
279 gc.fill = GridBagConstraints.BOTH;
280 gc.weightx = 1.0;
281 gc.weighty = 1.0;
282 add(new JPanel(), gc);
283 }
284
285 protected final void refreshView() {
286 String v = OAuthAccessTokenHolder.getInstance().getAccessTokenKey();
287 tfAccessTokenKey.setText(v == null ? "" : v);
288 v = OAuthAccessTokenHolder.getInstance().getAccessTokenSecret();
289 tfAccessTokenSecret.setText(v == null ? "" : v);
290 cbSaveToPreferences.setSelected(OAuthAccessTokenHolder.getInstance().isSaveToPreferences());
291 }
292 }
293
294 /**
295 * Action to authorise the current user
296 */
297 private class AuthoriseNowAction extends AbstractAction {
298 AuthoriseNowAction() {
299 putValue(NAME, tr("Authorize now"));
300 putValue(SHORT_DESCRIPTION, tr("Click to step through the OAuth authorization process"));
301 new ImageProvider("oauth", "oauth-small").getResource().attachImageIcon(this);
302 }
303
304 @Override
305 public void actionPerformed(ActionEvent arg0) {
306 OAuthAuthorizationWizard wizard = new OAuthAuthorizationWizard(
307 OAuthAuthenticationPreferencesPanel.this,
308 apiUrl,
309 MainApplication.worker);
310 try {
311 wizard.showDialog();
312 } catch (UserCancelException ignore) {
313 Logging.trace(ignore);
314 return;
315 }
316 pnlAdvancedProperties.setAdvancedParameters(wizard.getOAuthParameters());
317 refreshView();
318 }
319 }
320
321 /**
322 * Launches the OAuthAuthorisationWizard to generate a new Access Token
323 */
324 private class RenewAuthorisationAction extends AuthoriseNowAction {
325 /**
326 * Constructs a new {@code RenewAuthorisationAction}.
327 */
328 RenewAuthorisationAction() {
329 putValue(NAME, tr("New Access Token"));
330 putValue(SHORT_DESCRIPTION, tr("Click to step through the OAuth authorization process and generate a new Access Token"));
331 new ImageProvider("oauth", "oauth-small").getResource().attachImageIcon(this);
332 }
333 }
334
335 /**
336 * Runs a test whether we can access the OSM server with the current Access Token
337 */
338 private class TestAuthorisationAction extends AbstractAction {
339 /**
340 * Constructs a new {@code TestAuthorisationAction}.
341 */
342 TestAuthorisationAction() {
343 putValue(NAME, tr("Test Access Token"));
344 putValue(SHORT_DESCRIPTION, tr("Click test access to the OSM server with the current access token"));
345 new ImageProvider("oauth", "oauth-small").getResource().attachImageIcon(this);
346 }
347
348 @Override
349 public void actionPerformed(ActionEvent evt) {
350 OAuthToken token = OAuthAccessTokenHolder.getInstance().getAccessToken();
351 OAuthParameters parameters = OAuthParameters.createFromApiUrl(OsmApi.getOsmApi().getServerUrl());
352 TestAccessTokenTask task = new TestAccessTokenTask(
353 OAuthAuthenticationPreferencesPanel.this,
354 apiUrl,
355 parameters,
356 token
357 );
358 MainApplication.worker.submit(task);
359 }
360 }
361
362 @Override
363 public void propertyChange(PropertyChangeEvent evt) {
364 if (!evt.getPropertyName().equals(OsmApiUrlInputPanel.API_URL_PROP))
365 return;
366 setApiUrl((String) evt.getNewValue());
367 }
368}
Note: See TracBrowser for help on using the repository browser.