source: josm/trunk/src/org/openstreetmap/josm/gui/oauth/ManualAuthorizationUI.java@ 18650

Last change on this file since 18650 was 18650, checked in by taylor.smock, 16 months ago

Fix #20768: Add OAuth 2.0 support

This also fixes #21607: authentication buttons are unavailable when credentials
are set.

  • Property svn:eol-style set to native
File size: 9.0 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.oauth;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.BorderLayout;
7import java.awt.FlowLayout;
8import java.awt.GridBagConstraints;
9import java.awt.GridBagLayout;
10import java.awt.Insets;
11import java.awt.event.ActionEvent;
12import java.beans.PropertyChangeEvent;
13import java.beans.PropertyChangeListener;
14import java.util.concurrent.Executor;
15
16import javax.swing.AbstractAction;
17import javax.swing.BorderFactory;
18import javax.swing.JButton;
19import javax.swing.JCheckBox;
20import javax.swing.JLabel;
21import javax.swing.JPanel;
22import javax.swing.JTabbedPane;
23import javax.swing.event.DocumentEvent;
24import javax.swing.event.DocumentListener;
25import javax.swing.text.JTextComponent;
26
27import org.openstreetmap.josm.data.oauth.OAuthAccessTokenHolder;
28import org.openstreetmap.josm.data.oauth.OAuthParameters;
29import org.openstreetmap.josm.data.oauth.OAuthToken;
30import org.openstreetmap.josm.gui.widgets.DefaultTextComponentValidator;
31import org.openstreetmap.josm.gui.widgets.HtmlPanel;
32import org.openstreetmap.josm.gui.widgets.JosmTextField;
33import org.openstreetmap.josm.gui.widgets.SelectAllOnFocusGainedDecorator;
34import org.openstreetmap.josm.tools.ImageProvider;
35
36/**
37 * This is an UI which supports a JOSM user to get an OAuth Access Token in a fully manual process.
38 *
39 * @since 2746
40 */
41public class ManualAuthorizationUI extends AbstractAuthorizationUI {
42
43 private final JosmTextField tfAccessTokenKey = new JosmTextField();
44 private transient AccessTokenKeyValidator valAccessTokenKey;
45 private final JosmTextField tfAccessTokenSecret = new JosmTextField();
46 private transient AccessTokenSecretValidator valAccessTokenSecret;
47 private final JCheckBox cbSaveToPreferences = new JCheckBox(tr("Save Access Token in preferences"));
48 private final HtmlPanel pnlMessage = new HtmlPanel();
49 private final transient Executor executor;
50
51 /**
52 * Constructs a new {@code ManualAuthorizationUI} for the given API URL.
53 * @param apiUrl The OSM API URL
54 * @param executor the executor used for running the HTTP requests for the authorization
55 * @since 5422
56 */
57 public ManualAuthorizationUI(String apiUrl, Executor executor) {
58 super(/* dont pass apiURL because setApiUrl is overridden and references a local field */);
59 setApiUrl(apiUrl);
60 this.executor = executor;
61 build();
62 }
63
64 protected JPanel buildAccessTokenPanel() {
65 JPanel pnl = new JPanel(new GridBagLayout());
66 pnl.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
67 GridBagConstraints gc = new GridBagConstraints();
68 AccessTokenBuilder accessTokenBuilder = new AccessTokenBuilder();
69
70 // the access token key input field
71 gc.anchor = GridBagConstraints.NORTHWEST;
72 gc.fill = GridBagConstraints.HORIZONTAL;
73 gc.weightx = 0.0;
74 gc.gridwidth = 2;
75 gc.insets = new Insets(0, 0, 5, 0);
76 pnlMessage.setText("<html><body>"
77 + tr("Please enter an OAuth Access Token which is authorized to access the OSM server "
78 + "''{0}''.",
79 getApiUrl()) + "</body></html>");
80 pnl.add(pnlMessage, gc);
81
82 // the access token key input field
83 gc.gridy = 1;
84 gc.weightx = 0.0;
85 gc.gridwidth = 1;
86 gc.insets = new Insets(0, 0, 0, 3);
87 pnl.add(new JLabel(tr("Access Token Key:")), gc);
88
89 gc.gridx = 1;
90 gc.weightx = 1.0;
91 pnl.add(tfAccessTokenKey, gc);
92 SelectAllOnFocusGainedDecorator.decorate(tfAccessTokenKey);
93 valAccessTokenKey = new AccessTokenKeyValidator(tfAccessTokenKey);
94 valAccessTokenKey.validate();
95 tfAccessTokenKey.getDocument().addDocumentListener(accessTokenBuilder);
96
97 // the access token key input field
98 gc.gridy = 2;
99 gc.gridx = 0;
100 gc.weightx = 0.0;
101 pnl.add(new JLabel(tr("Access Token Secret:")), gc);
102
103 gc.gridx = 1;
104 gc.weightx = 1.0;
105 pnl.add(tfAccessTokenSecret, gc);
106 SelectAllOnFocusGainedDecorator.decorate(tfAccessTokenSecret);
107 valAccessTokenSecret = new AccessTokenSecretValidator(tfAccessTokenSecret);
108 valAccessTokenSecret.validate();
109 tfAccessTokenSecret.getDocument().addDocumentListener(accessTokenBuilder);
110
111 // the checkbox for saving to preferences
112 gc.gridy = 3;
113 gc.gridx = 0;
114 gc.gridwidth = 2;
115 gc.weightx = 1.0;
116 pnl.add(cbSaveToPreferences, gc);
117 cbSaveToPreferences.setSelected(OAuthAccessTokenHolder.getInstance().isSaveToPreferences());
118
119 // filler - grab remaining space
120 gc.gridy = 3;
121 gc.gridx = 0;
122 gc.gridwidth = 2;
123 gc.weightx = 1.0;
124 gc.weighty = 1.0;
125 gc.fill = GridBagConstraints.BOTH;
126 pnl.add(new JPanel(), gc);
127 return pnl;
128 }
129
130 protected JPanel buildTabbedPreferencesPanel() {
131 JPanel pnl = new JPanel(new BorderLayout());
132
133 JTabbedPane tp = new JTabbedPane();
134 tp.add(buildAccessTokenPanel());
135 tp.add(getAdvancedPropertiesPanel());
136
137 tp.setTitleAt(0, tr("Access Token"));
138 tp.setTitleAt(1, tr("Advanced OAuth parameters"));
139
140 tp.setToolTipTextAt(0, tr("Enter the OAuth Access Token"));
141 tp.setToolTipTextAt(1, tr("Enter advanced OAuth properties"));
142
143 pnl.add(tp, BorderLayout.CENTER);
144 return pnl;
145 }
146
147 protected JPanel buildActionsPanel() {
148 JPanel pnl = new JPanel(new FlowLayout(FlowLayout.LEFT));
149 TestAccessTokenAction actTestAccessToken = new TestAccessTokenAction();
150 pnl.add(new JButton(actTestAccessToken));
151 this.addPropertyChangeListener(actTestAccessToken);
152 return pnl;
153 }
154
155 @Override
156 public void setApiUrl(String apiUrl) {
157 super.setApiUrl(apiUrl);
158 if (pnlMessage != null) {
159 pnlMessage.setText(tr("<html><body>"
160 + "Please enter an OAuth Access Token which is authorized to access the OSM server "
161 + "''{0}''."
162 + "</body></html>",
163 getApiUrl()
164 ));
165 }
166 }
167
168 protected final void build() {
169 setLayout(new BorderLayout());
170 setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
171 add(buildTabbedPreferencesPanel(), BorderLayout.CENTER);
172 add(buildActionsPanel(), BorderLayout.SOUTH);
173 }
174
175 @Override
176 public boolean isSaveAccessTokenToPreferences() {
177 return cbSaveToPreferences.isSelected();
178 }
179
180 private static class AccessTokenKeyValidator extends DefaultTextComponentValidator {
181 AccessTokenKeyValidator(JTextComponent tc) {
182 super(tc, tr("Please enter an Access Token Key"),
183 tr("The Access Token Key must not be empty. Please enter an Access Token Key"));
184 }
185 }
186
187 private static class AccessTokenSecretValidator extends DefaultTextComponentValidator {
188 AccessTokenSecretValidator(JTextComponent tc) {
189 super(tc, tr("Please enter an Access Token Secret"),
190 tr("The Access Token Secret must not be empty. Please enter an Access Token Secret"));
191 }
192 }
193
194 class AccessTokenBuilder implements DocumentListener {
195
196 public void build() {
197 if (!valAccessTokenKey.isValid() || !valAccessTokenSecret.isValid()) {
198 setAccessToken(null);
199 } else {
200 setAccessToken(new OAuthToken(tfAccessTokenKey.getText().trim(), tfAccessTokenSecret.getText().trim()));
201 }
202 }
203
204 @Override
205 public void changedUpdate(DocumentEvent e) {
206 build();
207 }
208
209 @Override
210 public void insertUpdate(DocumentEvent e) {
211 build();
212 }
213
214 @Override
215 public void removeUpdate(DocumentEvent e) {
216 build();
217 }
218 }
219
220 /**
221 * Action for testing an Access Token
222 */
223 class TestAccessTokenAction extends AbstractAction implements PropertyChangeListener {
224 TestAccessTokenAction() {
225 putValue(NAME, tr("Test Access Token"));
226 new ImageProvider("oauth", "oauth-small").getResource().attachImageIcon(this);
227 putValue(SHORT_DESCRIPTION, tr("Click to test the Access Token"));
228 updateEnabledState();
229 }
230
231 @Override
232 public void actionPerformed(ActionEvent evt) {
233 TestAccessTokenTask task = new TestAccessTokenTask(
234 ManualAuthorizationUI.this,
235 getApiUrl(),
236 (OAuthParameters) getAdvancedPropertiesPanel().getAdvancedParameters(),
237 getAccessToken()
238 );
239 executor.execute(task);
240 }
241
242 protected final void updateEnabledState() {
243 setEnabled(hasAccessToken());
244 }
245
246 @Override
247 public void propertyChange(PropertyChangeEvent evt) {
248 if (!evt.getPropertyName().equals(AbstractAuthorizationUI.ACCESS_TOKEN_PROP))
249 return;
250 updateEnabledState();
251 }
252 }
253}
Note: See TracBrowser for help on using the repository browser.