source: josm/trunk/src/org/openstreetmap/josm/io/OsmConnection.java@ 12288

Last change on this file since 12288 was 11544, checked in by Don-vip, 7 years ago

sonar - squid:S1854 - Dead stores should be removed

  • Property svn:eol-style set to native
File size: 6.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.lang.reflect.InvocationTargetException;
7import java.net.Authenticator.RequestorType;
8import java.net.MalformedURLException;
9import java.net.URL;
10import java.nio.charset.StandardCharsets;
11import java.util.Base64;
12import java.util.Objects;
13import java.util.concurrent.FutureTask;
14
15import javax.swing.SwingUtilities;
16
17import org.openstreetmap.josm.Main;
18import org.openstreetmap.josm.data.oauth.OAuthParameters;
19import org.openstreetmap.josm.gui.oauth.OAuthAuthorizationWizard;
20import org.openstreetmap.josm.gui.preferences.server.OAuthAccessTokenHolder;
21import org.openstreetmap.josm.io.auth.CredentialsAgentException;
22import org.openstreetmap.josm.io.auth.CredentialsAgentResponse;
23import org.openstreetmap.josm.io.auth.CredentialsManager;
24import org.openstreetmap.josm.tools.HttpClient;
25import org.openstreetmap.josm.tools.Utils;
26
27import oauth.signpost.OAuthConsumer;
28import oauth.signpost.exception.OAuthException;
29
30/**
31 * Base class that handles common things like authentication for the reader and writer
32 * to the osm server.
33 *
34 * @author imi
35 */
36public class OsmConnection {
37 protected boolean cancel;
38 protected HttpClient activeConnection;
39 protected OAuthParameters oauthParameters;
40
41 /**
42 * Cancels the connection.
43 */
44 public void cancel() {
45 cancel = true;
46 synchronized (this) {
47 if (activeConnection != null) {
48 activeConnection.disconnect();
49 }
50 }
51 }
52
53 /**
54 * Adds an authentication header for basic authentication
55 *
56 * @param con the connection
57 * @throws OsmTransferException if something went wrong. Check for nested exceptions
58 */
59 protected void addBasicAuthorizationHeader(HttpClient con) throws OsmTransferException {
60 CredentialsAgentResponse response;
61 try {
62 synchronized (CredentialsManager.getInstance()) {
63 response = CredentialsManager.getInstance().getCredentials(RequestorType.SERVER,
64 con.getURL().getHost(), false /* don't know yet whether the credentials will succeed */);
65 }
66 } catch (CredentialsAgentException e) {
67 throw new OsmTransferException(e);
68 }
69 if (response != null) {
70 if (response.isCanceled()) {
71 cancel = true;
72 return;
73 } else {
74 String username = response.getUsername() == null ? "" : response.getUsername();
75 String password = response.getPassword() == null ? "" : String.valueOf(response.getPassword());
76 String token = username + ':' + password;
77 con.setHeader("Authorization", "Basic "+Base64.getEncoder().encodeToString(token.getBytes(StandardCharsets.UTF_8)));
78 }
79 }
80 }
81
82 /**
83 * Signs the connection with an OAuth authentication header
84 *
85 * @param connection the connection
86 *
87 * @throws OsmTransferException if there is currently no OAuth Access Token configured
88 * @throws OsmTransferException if signing fails
89 */
90 protected void addOAuthAuthorizationHeader(HttpClient connection) throws OsmTransferException {
91 if (oauthParameters == null) {
92 oauthParameters = OAuthParameters.createFromPreferences(Main.pref);
93 }
94 OAuthConsumer consumer = oauthParameters.buildConsumer();
95 OAuthAccessTokenHolder holder = OAuthAccessTokenHolder.getInstance();
96 if (!holder.containsAccessToken()) {
97 obtainAccessToken(connection);
98 }
99 if (!holder.containsAccessToken()) { // check if wizard completed
100 throw new MissingOAuthAccessTokenException();
101 }
102 consumer.setTokenWithSecret(holder.getAccessTokenKey(), holder.getAccessTokenSecret());
103 try {
104 consumer.sign(connection);
105 } catch (OAuthException e) {
106 throw new OsmTransferException(tr("Failed to sign a HTTP connection with an OAuth Authentication header"), e);
107 }
108 }
109
110 /**
111 * Obtains an OAuth access token for the connection. Afterwards, the token is accessible via {@link OAuthAccessTokenHolder}.
112 * @param connection connection for which the access token should be obtained
113 * @throws MissingOAuthAccessTokenException if the process cannot be completec successfully
114 */
115 protected void obtainAccessToken(final HttpClient connection) throws MissingOAuthAccessTokenException {
116 try {
117 final URL apiUrl = new URL(OsmApi.getOsmApi().getServerUrl());
118 if (!Objects.equals(apiUrl.getHost(), connection.getURL().getHost())) {
119 throw new MissingOAuthAccessTokenException();
120 }
121 final Runnable authTask = new FutureTask<>(() -> {
122 // Concerning Utils.newDirectExecutor: Main.worker cannot be used since this connection is already
123 // executed via Main.worker. The OAuth connections would block otherwise.
124 final OAuthAuthorizationWizard wizard = new OAuthAuthorizationWizard(
125 Main.parent, apiUrl.toExternalForm(), Utils.newDirectExecutor());
126 wizard.showDialog();
127 OAuthAccessTokenHolder.getInstance().setSaveToPreferences(true);
128 OAuthAccessTokenHolder.getInstance().save(Main.pref, CredentialsManager.getInstance());
129 return wizard;
130 });
131 // exception handling differs from implementation at GuiHelper.runInEDTAndWait()
132 if (SwingUtilities.isEventDispatchThread()) {
133 authTask.run();
134 } else {
135 SwingUtilities.invokeAndWait(authTask);
136 }
137 } catch (MalformedURLException | InterruptedException | InvocationTargetException e) {
138 throw new MissingOAuthAccessTokenException(e);
139 }
140 }
141
142 protected void addAuth(HttpClient connection) throws OsmTransferException {
143 final String authMethod = OsmApi.getAuthMethod();
144 if ("basic".equals(authMethod)) {
145 addBasicAuthorizationHeader(connection);
146 } else if ("oauth".equals(authMethod)) {
147 addOAuthAuthorizationHeader(connection);
148 } else {
149 String msg = tr("Unexpected value for preference ''{0}''. Got ''{1}''.", "osm-server.auth-method", authMethod);
150 Main.warn(msg);
151 throw new OsmTransferException(msg);
152 }
153 }
154
155 /**
156 * Replies true if this connection is canceled
157 *
158 * @return true if this connection is canceled
159 */
160 public boolean isCanceled() {
161 return cancel;
162 }
163}
Note: See TracBrowser for help on using the repository browser.