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

Last change on this file since 14206 was 13901, checked in by Don-vip, 6 years ago

add new XmlUtils class with more "safe factories" methods

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