source: josm/trunk/src/org/openstreetmap/josm/io/remotecontrol/RemoteControlHttpsServer.java@ 7037

Last change on this file since 7037 was 7037, checked in by Don-vip, 10 years ago

see #8465 - last batch of try-with-resources

File size: 8.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.io.remotecontrol;
3
4import static org.openstreetmap.josm.tools.I18n.marktr;
5import static org.openstreetmap.josm.tools.I18n.tr;
6
7import java.io.IOException;
8import java.io.InputStream;
9import java.net.BindException;
10import java.net.InetAddress;
11import java.net.ServerSocket;
12import java.net.Socket;
13import java.net.SocketException;
14import java.security.KeyManagementException;
15import java.security.KeyStore;
16import java.security.KeyStoreException;
17import java.security.NoSuchAlgorithmException;
18import java.security.UnrecoverableKeyException;
19import java.security.cert.CertificateException;
20import java.util.Arrays;
21import java.util.Enumeration;
22
23import javax.net.ssl.KeyManagerFactory;
24import javax.net.ssl.SSLContext;
25import javax.net.ssl.SSLServerSocket;
26import javax.net.ssl.SSLServerSocketFactory;
27import javax.net.ssl.SSLSocket;
28import javax.net.ssl.TrustManagerFactory;
29
30import org.openstreetmap.josm.Main;
31
32/**
33 * Simple HTTPS server that spawns a {@link RequestProcessor} for every secure connection.
34 *
35 * @since 6941
36 */
37public class RemoteControlHttpsServer extends Thread {
38
39 /** The server socket */
40 private ServerSocket server;
41
42 private static RemoteControlHttpsServer instance;
43 private boolean initOK = false;
44 private SSLContext sslContext;
45
46 private static final String KEYSTORE_PATH = "/data/josm.keystore";
47 private static final String KEYSTORE_PASSWORD = "josm_ssl";
48
49 private void initialize() {
50 if (!initOK) {
51 try {
52 // Create new keystore
53 KeyStore ks = KeyStore.getInstance("JKS");
54 char[] password = KEYSTORE_PASSWORD.toCharArray();
55
56 // Load keystore
57 try (InputStream in = RemoteControlHttpsServer.class.getResourceAsStream(KEYSTORE_PATH)) {
58 if (in == null) {
59 Main.error(tr("Unable to find JOSM keystore at {0}. Remote control will not be available on HTTPS.", KEYSTORE_PATH));
60 } else {
61 ks.load(in, password);
62
63 if (Main.isDebugEnabled()) {
64 for (Enumeration<String> aliases = ks.aliases(); aliases.hasMoreElements();) {
65 Main.debug("Alias in keystore: "+aliases.nextElement());
66 }
67 }
68
69 KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
70 kmf.init(ks, password);
71
72 TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");
73 tmf.init(ks);
74
75 sslContext = SSLContext.getInstance("TLS");
76 sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
77
78 if (Main.isDebugEnabled()) {
79 Main.debug("SSL Context protocol: " + sslContext.getProtocol());
80 Main.debug("SSL Context provider: " + sslContext.getProvider());
81 }
82
83 initOK = true;
84 }
85 }
86 } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException |
87 IOException | UnrecoverableKeyException | KeyManagementException e) {
88 Main.error(e);
89 }
90 }
91 }
92
93 /**
94 * Starts or restarts the HTTPS server
95 */
96 public static void restartRemoteControlHttpsServer() {
97 int port = Main.pref.getInteger("remote.control.https.port", 8112);
98 try {
99 stopRemoteControlHttpsServer();
100
101 instance = new RemoteControlHttpsServer(port);
102 if (instance.initOK) {
103 instance.start();
104 }
105 } catch (BindException ex) {
106 Main.warn(marktr("Cannot start remotecontrol https server on port {0}: {1}"),
107 Integer.toString(port), ex.getLocalizedMessage());
108 } catch (IOException ioe) {
109 Main.error(ioe);
110 } catch (NoSuchAlgorithmException e) {
111 Main.error(e);
112 }
113 }
114
115 /**
116 * Stops the HTTPS server
117 */
118 public static void stopRemoteControlHttpsServer() {
119 if (instance != null) {
120 try {
121 instance.stopServer();
122 instance = null;
123 } catch (IOException ioe) {
124 Main.error(ioe);
125 }
126 }
127 }
128
129 /**
130 * Constructs a new {@code RemoteControlHttpsServer}.
131 * @param port The port this server will listen on
132 * @throws IOException when connection errors
133 * @throws NoSuchAlgorithmException if the JVM does not support TLS (can not happen)
134 */
135 public RemoteControlHttpsServer(int port) throws IOException, NoSuchAlgorithmException {
136 super("RemoteControl HTTPS Server");
137 this.setDaemon(true);
138
139 initialize();
140
141 // Create SSL Server factory
142 SSLServerSocketFactory factory = sslContext.getServerSocketFactory();
143 if (Main.isDebugEnabled()) {
144 Main.debug("SSL factory - Supported Cipher suites: "+Arrays.toString(factory.getSupportedCipherSuites()));
145 }
146
147 // Start the server socket with only 1 connection.
148 // Also make sure we only listen
149 // on the local interface so nobody from the outside can connect!
150 // NOTE: On a dual stack machine with old Windows OS this may not listen on both interfaces!
151 this.server = factory.createServerSocket(port, 1,
152 InetAddress.getByName(Main.pref.get("remote.control.host", "localhost")));
153
154 if (Main.isDebugEnabled() && server instanceof SSLServerSocket) {
155 SSLServerSocket sslServer = (SSLServerSocket) server;
156 Main.debug("SSL server - Enabled Cipher suites: "+Arrays.toString(sslServer.getEnabledCipherSuites()));
157 Main.debug("SSL server - Enabled Protocols: "+Arrays.toString(sslServer.getEnabledProtocols()));
158 Main.debug("SSL server - Enable Session Creation: "+sslServer.getEnableSessionCreation());
159 Main.debug("SSL server - Need Client Auth: "+sslServer.getNeedClientAuth());
160 Main.debug("SSL server - Want Client Auth: "+sslServer.getWantClientAuth());
161 Main.debug("SSL server - Use Client Mode: "+sslServer.getUseClientMode());
162 }
163 }
164
165 /**
166 * The main loop, spawns a {@link RequestProcessor} for each connection.
167 */
168 @Override
169 public void run() {
170 Main.info(marktr("RemoteControl::Accepting secure connections on port {0}"),
171 Integer.toString(server.getLocalPort()));
172 while (true) {
173 try {
174 @SuppressWarnings("resource")
175 Socket request = server.accept();
176 if (Main.isDebugEnabled() && request instanceof SSLSocket) {
177 SSLSocket sslSocket = (SSLSocket) request;
178 Main.debug("SSL socket - Enabled Cipher suites: "+Arrays.toString(sslSocket.getEnabledCipherSuites()));
179 Main.debug("SSL socket - Enabled Protocols: "+Arrays.toString(sslSocket.getEnabledProtocols()));
180 Main.debug("SSL socket - Enable Session Creation: "+sslSocket.getEnableSessionCreation());
181 Main.debug("SSL socket - Need Client Auth: "+sslSocket.getNeedClientAuth());
182 Main.debug("SSL socket - Want Client Auth: "+sslSocket.getWantClientAuth());
183 Main.debug("SSL socket - Use Client Mode: "+sslSocket.getUseClientMode());
184 Main.debug("SSL socket - Session: "+sslSocket.getSession());
185 }
186 RequestProcessor.processRequest(request);
187 } catch (SocketException se) {
188 if (!server.isClosed()) {
189 Main.error(se);
190 }
191 } catch (IOException ioe) {
192 Main.error(ioe);
193 }
194 }
195 }
196
197 /**
198 * Stops the HTTPS server.
199 *
200 * @throws IOException if any I/O error occurs
201 */
202 public void stopServer() throws IOException {
203 server.close();
204 Main.info(marktr("RemoteControl::Server (https) stopped."));
205 }
206}
Note: See TracBrowser for help on using the repository browser.