source: josm/trunk/src/org/openstreetmap/josm/gui/oauth/TestAccessTokenTask.java@ 18918

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

Fix #23290: Validate the regions a tag is expected to be in (patch by Sarabjeet108, modified)

Modifications are as follows:

  • Allow the use of the new region attributes for keys inside a preset
  • Basic tests

regions comes from Vespucci's extensions: https://vespucci.io/tutorials/presets/#extensions

  • Property svn:eol-style set to native
File size: 13.3 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.Component;
7import java.io.IOException;
8import java.net.HttpURLConnection;
9import java.net.URL;
10
11import javax.swing.JOptionPane;
12import javax.xml.parsers.ParserConfigurationException;
13
14import org.openstreetmap.josm.data.oauth.IOAuthParameters;
15import org.openstreetmap.josm.data.oauth.IOAuthToken;
16import org.openstreetmap.josm.data.oauth.OAuth20Token;
17import org.openstreetmap.josm.data.oauth.OAuthParameters;
18import org.openstreetmap.josm.data.oauth.OAuthToken;
19import org.openstreetmap.josm.data.osm.UserInfo;
20import org.openstreetmap.josm.gui.HelpAwareOptionPane;
21import org.openstreetmap.josm.gui.PleaseWaitRunnable;
22import org.openstreetmap.josm.gui.help.HelpUtil;
23import org.openstreetmap.josm.io.OsmApiException;
24import org.openstreetmap.josm.io.OsmServerUserInfoReader;
25import org.openstreetmap.josm.io.OsmTransferException;
26import org.openstreetmap.josm.io.auth.DefaultAuthenticator;
27import org.openstreetmap.josm.tools.CheckParameterUtil;
28import org.openstreetmap.josm.tools.HttpClient;
29import org.openstreetmap.josm.tools.Logging;
30import org.openstreetmap.josm.tools.Utils;
31import org.openstreetmap.josm.tools.XmlParsingException;
32import org.openstreetmap.josm.tools.XmlUtils;
33import org.w3c.dom.Document;
34import org.xml.sax.SAXException;
35
36import oauth.signpost.OAuthConsumer;
37import oauth.signpost.exception.OAuthException;
38
39/**
40 * Checks whether an OSM API server can be accessed with a specific Access Token.
41 *
42 * It retrieves the user details for the user which is authorized to access the server with
43 * this token.
44 *
45 */
46public class TestAccessTokenTask extends PleaseWaitRunnable {
47 private final OAuthToken tokenOAuth1;
48 private final IOAuthToken tokenOAuth2;
49 private final IOAuthParameters oauthParameters;
50 private boolean canceled;
51 private final Component parent;
52 private final String apiUrl;
53 private HttpClient connection;
54
55 /**
56 * Create the task
57 *
58 * @param parent the parent component relative to which the {@link PleaseWaitRunnable}-Dialog is displayed
59 * @param apiUrl the API URL. Must not be null.
60 * @param parameters the OAuth parameters. Must not be null.
61 * @param accessToken the Access Token. Must not be null.
62 */
63 public TestAccessTokenTask(Component parent, String apiUrl, OAuthParameters parameters, OAuthToken accessToken) {
64 super(parent, tr("Testing OAuth Access Token"), false /* don't ignore exceptions */);
65 CheckParameterUtil.ensureParameterNotNull(apiUrl, "apiUrl");
66 CheckParameterUtil.ensureParameterNotNull(parameters, "parameters");
67 CheckParameterUtil.ensureParameterNotNull(accessToken, "accessToken");
68 this.tokenOAuth1 = accessToken;
69 this.tokenOAuth2 = null;
70 this.oauthParameters = parameters;
71 this.parent = parent;
72 this.apiUrl = apiUrl;
73 }
74
75 /**
76 * Create the task
77 *
78 * @param parent the parent component relative to which the {@link PleaseWaitRunnable}-Dialog is displayed
79 * @param apiUrl the API URL. Must not be null.
80 * @param parameters the OAuth parameters. Must not be null.
81 * @param accessToken the Access Token. Must not be null.
82 * @since 18764
83 */
84 public TestAccessTokenTask(Component parent, String apiUrl, IOAuthParameters parameters, IOAuthToken accessToken) {
85 super(parent, tr("Testing OAuth Access Token"), false /* don't ignore exceptions */);
86 CheckParameterUtil.ensureParameterNotNull(apiUrl, "apiUrl");
87 CheckParameterUtil.ensureParameterNotNull(parameters, "parameters");
88 CheckParameterUtil.ensureParameterNotNull(accessToken, "accessToken");
89 this.tokenOAuth1 = null;
90 this.tokenOAuth2 = accessToken;
91 this.oauthParameters = parameters;
92 this.parent = parent;
93 this.apiUrl = apiUrl;
94 }
95
96 @Override
97 protected void cancel() {
98 canceled = true;
99 synchronized (this) {
100 if (connection != null) {
101 connection.disconnect();
102 }
103 }
104 }
105
106 @Override
107 protected void finish() {
108 // Do nothing
109 }
110
111 protected void sign(HttpClient con) throws OAuthException {
112 if (oauthParameters instanceof OAuthParameters) {
113 OAuthConsumer consumer = ((OAuthParameters) oauthParameters).buildConsumer();
114 consumer.setTokenWithSecret(tokenOAuth1.getKey(), tokenOAuth1.getSecret());
115 consumer.sign(con);
116 } else {
117 try {
118 this.tokenOAuth2.sign(con);
119 } catch (org.openstreetmap.josm.data.oauth.OAuthException e) {
120 // Adapt our OAuthException to the SignPost OAuth exception
121 throw new OAuthException(e) {};
122 }
123 }
124 }
125
126 protected String normalizeApiUrl(String url) {
127 // remove leading and trailing white space
128 url = url.trim();
129
130 // remove trailing slashes
131 while (url.endsWith("/")) {
132 url = url.substring(0, url.lastIndexOf('/'));
133 }
134 return url;
135 }
136
137 protected UserInfo getUserDetails() throws OsmOAuthAuthorizationException, XmlParsingException, OsmTransferException {
138 boolean authenticatorEnabled = true;
139 try {
140 URL url = new URL(normalizeApiUrl(apiUrl) + "/0.6/user/details");
141 authenticatorEnabled = DefaultAuthenticator.getInstance().isEnabled();
142 DefaultAuthenticator.getInstance().setEnabled(false);
143
144 final HttpClient client = HttpClient.create(url);
145 sign(client);
146 synchronized (this) {
147 connection = client;
148 connection.connect();
149 }
150
151 final String oauthKey = getAuthKey();
152 if (connection.getResponse().getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED)
153 throw new OsmApiException(HttpURLConnection.HTTP_UNAUTHORIZED,
154 tr("Retrieving user details with Access Token Key ''{0}'' was rejected.",
155 oauthKey), null);
156
157 if (connection.getResponse().getResponseCode() == HttpURLConnection.HTTP_FORBIDDEN)
158 throw new OsmApiException(HttpURLConnection.HTTP_FORBIDDEN,
159 tr("Retrieving user details with Access Token Key ''{0}'' was forbidden.", oauthKey), null);
160
161 if (connection.getResponse().getResponseCode() != HttpURLConnection.HTTP_OK)
162 throw new OsmApiException(connection.getResponse().getResponseCode(),
163 connection.getResponse().getHeaderField("Error"), null);
164 Document d = XmlUtils.parseSafeDOM(connection.getResponse().getContent());
165 return OsmServerUserInfoReader.buildFromXML(d);
166 } catch (SAXException | ParserConfigurationException e) {
167 throw new XmlParsingException(e);
168 } catch (IOException e) {
169 throw new OsmTransferException(e);
170 } catch (OAuthException e) {
171 throw new OsmOAuthAuthorizationException(e);
172 } finally {
173 DefaultAuthenticator.getInstance().setEnabled(authenticatorEnabled);
174 }
175 }
176
177 protected void notifySuccess(UserInfo userInfo) {
178 HelpAwareOptionPane.showMessageDialogInEDT(
179 parent,
180 tr("<html>"
181 + "Successfully used the Access Token ''{0}'' to<br>"
182 + "access the OSM server at ''{1}''.<br>"
183 + "You are accessing the OSM server as user ''{2}'' with id ''{3}''."
184 + "</html>",
185 getAuthKey(),
186 apiUrl,
187 Utils.escapeReservedCharactersHTML(userInfo.getDisplayName()),
188 userInfo.getId()
189 ),
190 tr("Success"),
191 JOptionPane.INFORMATION_MESSAGE,
192 HelpUtil.ht("/Dialog/OAuthAuthorisationWizard#AccessTokenOK")
193 );
194 }
195
196 protected void alertFailedAuthentication() {
197 HelpAwareOptionPane.showMessageDialogInEDT(
198 parent,
199 tr("<html>"
200 + "Failed to access the OSM server ''{0}''<br>"
201 + "with the Access Token ''{1}''.<br>"
202 + "The server rejected the Access Token as unauthorized. You will not<br>"
203 + "be able to access any protected resource on this server using this token."
204 +"</html>",
205 apiUrl,
206 getAuthKey()
207 ),
208 tr("Test failed"),
209 JOptionPane.ERROR_MESSAGE,
210 HelpUtil.ht("/Dialog/OAuthAuthorisationWizard#AccessTokenFailed")
211 );
212 }
213
214 protected void alertFailedAuthorisation() {
215 HelpAwareOptionPane.showMessageDialogInEDT(
216 parent,
217 tr("<html>"
218 + "The Access Token ''{1}'' is known to the OSM server ''{0}''.<br>"
219 + "The test to retrieve the user details for this token failed, though.<br>"
220 + "Depending on what rights are granted to this token you may nevertheless use it<br>"
221 + "to upload data, upload GPS traces, and/or access other protected resources."
222 +"</html>",
223 apiUrl,
224 getAuthKey()
225 ),
226 tr("Token allows restricted access"),
227 JOptionPane.WARNING_MESSAGE,
228 HelpUtil.ht("/Dialog/OAuthAuthorisationWizard#AccessTokenFailed")
229 );
230 }
231
232 protected void alertFailedConnection() {
233 HelpAwareOptionPane.showMessageDialogInEDT(
234 parent,
235 tr("<html>"
236 + "Failed to retrieve information about the current user"
237 + " from the OSM server ''{0}''.<br>"
238 + "This is probably not a problem caused by the tested Access Token, but<br>"
239 + "rather a problem with the server configuration. Carefully check the server<br>"
240 + "URL and your Internet connection."
241 +"</html>",
242 apiUrl,
243 getAuthKey()
244 ),
245 tr("Test failed"),
246 JOptionPane.ERROR_MESSAGE,
247 HelpUtil.ht("/Dialog/OAuthAuthorisationWizard#AccessTokenFailed")
248 );
249 }
250
251 protected void alertFailedSigning() {
252 HelpAwareOptionPane.showMessageDialogInEDT(
253 parent,
254 tr("<html>"
255 + "Failed to sign the request for the OSM server ''{0}'' with the "
256 + "token ''{1}''.<br>"
257 + "The token ist probably invalid."
258 +"</html>",
259 apiUrl,
260 getAuthKey()
261 ),
262 tr("Test failed"),
263 JOptionPane.ERROR_MESSAGE,
264 HelpUtil.ht("/Dialog/OAuthAuthorisationWizard#AccessTokenFailed")
265 );
266 }
267
268 protected void alertInternalError() {
269 HelpAwareOptionPane.showMessageDialogInEDT(
270 parent,
271 tr("<html>"
272 + "The test failed because the server responded with an internal error.<br>"
273 + "JOSM could not decide whether the token is valid. Please try again later."
274 + "</html>",
275 apiUrl,
276 getAuthKey()
277 ),
278 tr("Test failed"),
279 JOptionPane.WARNING_MESSAGE,
280 HelpUtil.ht("/Dialog/OAuthAuthorisationWizard#AccessTokenFailed")
281 );
282 }
283
284 @Override
285 protected void realRun() throws SAXException, IOException, OsmTransferException {
286 try {
287 getProgressMonitor().indeterminateSubTask(tr("Retrieving user info..."));
288 UserInfo userInfo = getUserDetails();
289 if (canceled) return;
290 notifySuccess(userInfo);
291 } catch (OsmOAuthAuthorizationException e) {
292 if (canceled) return;
293 Logging.error(e);
294 alertFailedSigning();
295 } catch (OsmApiException e) {
296 if (canceled) return;
297 Logging.error(e);
298 if (e.getResponseCode() == HttpURLConnection.HTTP_INTERNAL_ERROR) {
299 alertInternalError();
300 return;
301 } else if (e.getResponseCode() == HttpURLConnection.HTTP_UNAUTHORIZED) {
302 alertFailedAuthentication();
303 return;
304 } else if (e.getResponseCode() == HttpURLConnection.HTTP_FORBIDDEN) {
305 alertFailedAuthorisation();
306 return;
307 }
308 alertFailedConnection();
309 } catch (OsmTransferException e) {
310 if (canceled) return;
311 Logging.error(e);
312 alertFailedConnection();
313 }
314 }
315
316 private String getAuthKey() {
317 if (this.tokenOAuth1 != null) {
318 return this.tokenOAuth1.getKey();
319 }
320 if (this.tokenOAuth2 instanceof OAuth20Token) {
321 return ((OAuth20Token) this.tokenOAuth2).getBearerToken();
322 }
323 throw new IllegalArgumentException("Only OAuth1 and OAuth2 tokens are understood: " + this.tokenOAuth2);
324 }
325}
Note: See TracBrowser for help on using the repository browser.