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

Last change on this file since 10568 was 10308, checked in by Don-vip, 8 years ago

sonar - squid:S1854 - Dead stores should be removed

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