|
4 | 4 | */
|
5 | 5 | package com.ibm.streamsx.inet.rest.engine;
|
6 | 6 |
|
| 7 | +import java.io.ByteArrayInputStream; |
7 | 8 | import java.io.File;
|
| 9 | +import java.io.IOException; |
| 10 | +import java.io.InputStream; |
8 | 11 | import java.lang.management.ManagementFactory;
|
9 | 12 | import java.net.URI;
|
| 13 | +import java.security.KeyStore; |
| 14 | +import java.security.KeyStoreException; |
| 15 | +import java.security.NoSuchAlgorithmException; |
| 16 | +import java.security.cert.CertificateException; |
10 | 17 | import java.util.ArrayList;
|
| 18 | +import java.util.Base64; |
11 | 19 | import java.util.Collections;
|
12 | 20 | import java.util.HashMap;
|
13 | 21 | import java.util.List;
|
14 | 22 | import java.util.Map;
|
| 23 | +import java.util.Base64.Decoder; |
15 | 24 | import java.util.concurrent.LinkedBlockingQueue;
|
16 | 25 | import java.util.concurrent.RejectedExecutionException;
|
17 | 26 | import java.util.concurrent.ThreadPoolExecutor;
|
|
49 | 58 | import org.eclipse.jetty.util.thread.ThreadPool;
|
50 | 59 |
|
51 | 60 | import com.ibm.streams.operator.OperatorContext;
|
| 61 | +import com.ibm.streams.operator.ProcessingElement; |
52 | 62 | import com.ibm.streams.operator.StreamingData;
|
53 | 63 | import com.ibm.streams.operator.management.OperatorManagement;
|
54 | 64 | import com.ibm.streamsx.inet.rest.ops.Functions;
|
@@ -87,6 +97,8 @@ public class ServletEngine implements ServletEngineMBean, MBeanRegistration {
|
87 | 97 |
|
88 | 98 | public static final String SSL_TRUSTSTORE_PARAM = "trustStore";
|
89 | 99 | public static final String SSL_TRUSTSTORE_PASSWORD_PARAM = "trustStorePassword";
|
| 100 | + |
| 101 | + public static final String SSL_APP_CONFIG_NAME_PARAM = "sslAppConfigName"; |
90 | 102 |
|
91 | 103 | public static final int IDLE_TIMEOUT = 30000;
|
92 | 104 | public static final int STRICT_TRANSPORT_SECURITY_MAX_AGE = 2000;
|
@@ -168,7 +180,8 @@ public void join() throws InterruptedException {
|
168 | 180 | server = new Server(tp);
|
169 | 181 | handlers = new ContextHandlerCollection();
|
170 | 182 |
|
171 |
| - if (operatorContext.getParameterNames().contains(SSL_CERT_ALIAS_PARAM)) |
| 183 | + if ( (operatorContext.getParameterNames().contains(SSL_CERT_ALIAS_PARAM)) |
| 184 | + || (operatorContext.getParameterNames().contains(SSL_APP_CONFIG_NAME_PARAM))) |
172 | 185 | setHTTPSConnector(operatorContext, server, portNumber, host);
|
173 | 186 | else
|
174 | 187 | setHTTPConnector(operatorContext, server, portNumber, host);
|
@@ -208,47 +221,102 @@ private void setHTTPConnector(OperatorContext operatorContext, Server server, in
|
208 | 221 |
|
209 | 222 | /**
|
210 | 223 | * Setup an HTTPS connector.
|
| 224 | + * @throws KeyStoreException |
| 225 | + * @throws IOException |
| 226 | + * @throws CertificateException |
| 227 | + * @throws NoSuchAlgorithmException |
211 | 228 | */
|
212 |
| - private void setHTTPSConnector(OperatorContext operatorContext, Server server, int httpsPort, String host) { |
| 229 | + private void setHTTPSConnector(OperatorContext operatorContext, Server server, int httpsPort, String host) |
| 230 | + throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException { |
213 | 231 | SslContextFactory.Server sslContextFactory = new SslContextFactory.Server();
|
214 |
| - //Key Store is required |
215 |
| - String keyStorePath = operatorContext.getParameterValues(SSL_KEYSTORE_PARAM).get(0); |
216 |
| - File keyStorePathFile = new File(keyStorePath); |
217 |
| - if (!keyStorePathFile.isAbsolute()) |
218 |
| - keyStorePathFile = new File(operatorContext.getPE().getApplicationDirectory(), keyStorePath); |
219 |
| - String keyStorePathToLoad = keyStorePathFile.getAbsolutePath(); |
220 |
| - System.out.println("keyStorePathToLoad=" + keyStorePathToLoad); |
221 |
| - sslContextFactory.setKeyStorePath(keyStorePathToLoad); |
222 |
| - //the key store password is optional |
223 |
| - if (operatorContext.getParameterNames().contains(SSL_KEYSTORE_PASSWORD_PARAM)) { |
224 |
| - String keyStorePassword = operatorContext.getParameterValues(SSL_KEYSTORE_PASSWORD_PARAM).get(0); |
225 |
| - System.out.println("keyStorePassword=****"); |
226 |
| - sslContextFactory.setKeyStorePassword(Functions.obfuscate(keyStorePassword)); |
227 |
| - } |
228 |
| - //Key password is required |
229 |
| - String keyPassword = operatorContext.getParameterValues(SSL_KEY_PASSWORD_PARAM).get(0); |
230 |
| - System.out.println("keyPassword=****"); |
231 |
| - sslContextFactory.setKeyManagerPassword(Functions.obfuscate(keyPassword)); |
232 |
| - //Key alias |
233 |
| - String alias = operatorContext.getParameterValues(SSL_CERT_ALIAS_PARAM).get(0); |
234 |
| - sslContextFactory.setCertAlias(alias); |
235 |
| - //Trust Store & password |
236 |
| - if (operatorContext.getParameterNames().contains(SSL_TRUSTSTORE_PARAM)) { |
237 |
| - String trustStorePath = operatorContext.getParameterValues(SSL_TRUSTSTORE_PARAM).get(0); |
238 |
| - File trustStorePathFile = new File(trustStorePath); |
239 |
| - if (!trustStorePathFile.isAbsolute()) |
240 |
| - trustStorePathFile = new File(operatorContext.getPE().getApplicationDirectory(), trustStorePath); |
241 |
| - String trustStorePathToLoad = trustStorePathFile.getAbsolutePath(); |
242 |
| - System.out.println("trustStorePathToLoad=" + trustStorePathToLoad); |
243 |
| - sslContextFactory.setTrustStorePath(trustStorePathToLoad); |
244 |
| - sslContextFactory.setNeedClientAuth(true); |
245 |
| - if (operatorContext.getParameterNames().contains(SSL_TRUSTSTORE_PASSWORD_PARAM)) { |
246 |
| - String trustStorePassword = operatorContext.getParameterValues(SSL_TRUSTSTORE_PASSWORD_PARAM).get(0); |
247 |
| - System.out.println("trustStorePassword=****"); |
248 |
| - sslContextFactory.setTrustStorePassword(Functions.obfuscate(trustStorePassword)); |
| 232 | + |
| 233 | + //ssl configuration with legacy parameters |
| 234 | + if (operatorContext.getParameterNames().contains(SSL_CERT_ALIAS_PARAM)) { |
| 235 | + |
| 236 | + //Key Store is required |
| 237 | + String keyStorePath = operatorContext.getParameterValues(SSL_KEYSTORE_PARAM).get(0); |
| 238 | + File keyStorePathFile = new File(keyStorePath); |
| 239 | + if (!keyStorePathFile.isAbsolute()) |
| 240 | + keyStorePathFile = new File(operatorContext.getPE().getApplicationDirectory(), keyStorePath); |
| 241 | + String keyStorePathToLoad = keyStorePathFile.getAbsolutePath(); |
| 242 | + System.out.println("keyStorePathToLoad=" + keyStorePathToLoad); |
| 243 | + sslContextFactory.setKeyStorePath(keyStorePathToLoad); |
| 244 | + |
| 245 | + //the key store password is optional |
| 246 | + if (operatorContext.getParameterNames().contains(SSL_KEYSTORE_PASSWORD_PARAM)) { |
| 247 | + String keyStorePassword = operatorContext.getParameterValues(SSL_KEYSTORE_PASSWORD_PARAM).get(0); |
| 248 | + System.out.println("keyStorePassword=****"); |
| 249 | + sslContextFactory.setKeyStorePassword(Functions.obfuscate(keyStorePassword)); |
| 250 | + } |
| 251 | + |
| 252 | + //Key password is required |
| 253 | + String keyPassword = operatorContext.getParameterValues(SSL_KEY_PASSWORD_PARAM).get(0); |
| 254 | + System.out.println("keyPassword=****"); |
| 255 | + sslContextFactory.setKeyManagerPassword(Functions.obfuscate(keyPassword)); |
| 256 | + |
| 257 | + //Key alias |
| 258 | + String alias = operatorContext.getParameterValues(SSL_CERT_ALIAS_PARAM).get(0); |
| 259 | + sslContextFactory.setCertAlias(alias); |
| 260 | + |
| 261 | + //Trust Store & password if necessary |
| 262 | + if (operatorContext.getParameterNames().contains(SSL_TRUSTSTORE_PARAM)) { |
| 263 | + String trustStorePath = operatorContext.getParameterValues(SSL_TRUSTSTORE_PARAM).get(0); |
| 264 | + File trustStorePathFile = new File(trustStorePath); |
| 265 | + if (!trustStorePathFile.isAbsolute()) |
| 266 | + trustStorePathFile = new File(operatorContext.getPE().getApplicationDirectory(), trustStorePath); |
| 267 | + String trustStorePathToLoad = trustStorePathFile.getAbsolutePath(); |
| 268 | + System.out.println("trustStorePathToLoad=" + trustStorePathToLoad); |
| 269 | + sslContextFactory.setTrustStorePath(trustStorePathToLoad); |
| 270 | + sslContextFactory.setNeedClientAuth(true); |
| 271 | + if (operatorContext.getParameterNames().contains(SSL_TRUSTSTORE_PASSWORD_PARAM)) { |
| 272 | + String trustStorePassword = operatorContext.getParameterValues(SSL_TRUSTSTORE_PASSWORD_PARAM).get(0); |
| 273 | + System.out.println("trustStorePassword=****"); |
| 274 | + sslContextFactory.setTrustStorePassword(Functions.obfuscate(trustStorePassword)); |
| 275 | + } |
| 276 | + } |
| 277 | + |
| 278 | + //Configuration with application configuration |
| 279 | + } else { |
| 280 | + |
| 281 | + ProcessingElement pe = operatorContext.getPE(); |
| 282 | + String certAppConfigName = operatorContext.getParameterValues(SSL_APP_CONFIG_NAME_PARAM).get(0); |
| 283 | + Map<String, String> certProps = pe.getApplicationConfiguration(certAppConfigName); |
| 284 | + System.out.println("streams-certs len: " + new Integer(certProps.size()).toString() + " keyset: " + certProps.keySet().toString()); |
| 285 | + if (certProps.isEmpty()) |
| 286 | + throw new IllegalArgumentException("app config with name " + certAppConfigName + " is required"); |
| 287 | + |
| 288 | + //Key Store and password is required |
| 289 | + if ( ! certProps.containsKey("server.jks")) |
| 290 | + throw new IllegalArgumentException("Property server.jks is required in app config " + certAppConfigName); |
| 291 | + String keyB64Str = certProps.get("server.jks"); |
| 292 | + Decoder decoder = Base64.getDecoder(); |
| 293 | + byte[] keyBytes = decoder.decode(keyB64Str); |
| 294 | + InputStream keyStream = new ByteArrayInputStream(keyBytes); |
| 295 | + |
| 296 | + if ( ! certProps.containsKey("server.pass")) |
| 297 | + throw new IllegalArgumentException("Property server.pass is required in app config " + certAppConfigName); |
| 298 | + String password = certProps.get("server.pass"); |
| 299 | + |
| 300 | + System.out.println("Load key store and passwd from app config " + certAppConfigName); |
| 301 | + KeyStore keyStore = KeyStore.getInstance("JKS"); |
| 302 | + keyStore.load(keyStream, password.toCharArray()); |
| 303 | + sslContextFactory.setKeyStore(keyStore); |
| 304 | + sslContextFactory.setKeyManagerPassword(password); |
| 305 | + |
| 306 | + //Set optionally trust material |
| 307 | + if (certProps.containsKey("cacerts.jks")) { |
| 308 | + String trustB64Str = certProps.get("cacerts.jks"); |
| 309 | + byte[] trustBytes = decoder.decode(trustB64Str); |
| 310 | + InputStream trustStream = new ByteArrayInputStream(trustBytes); |
| 311 | + |
| 312 | + System.out.println("Load trust store and passwd from app config " + certAppConfigName); |
| 313 | + KeyStore trustStore = KeyStore.getInstance("JKS"); |
| 314 | + trustStore.load(trustStream, password.toCharArray()); |
| 315 | + sslContextFactory.setTrustStore(trustStore); |
| 316 | + sslContextFactory.setNeedClientAuth(true); |
249 | 317 | }
|
250 | 318 | }
|
251 |
| - |
| 319 | + |
252 | 320 | sslContextFactory.setRenegotiationAllowed(false);
|
253 | 321 | sslContextFactory.setIncludeProtocols("TLSv1.2");
|
254 | 322 | String[] specs = {"^.*_(MD5|SHA|SHA1)$","^TLS_RSA_.*$","^.*_NULL_.*$","^.*_anon_.*$"};
|
|
0 commit comments