001: package org.objectweb.celtix.bus.transports.https;
002:
003: import java.io.ByteArrayInputStream;
004: import java.io.ByteArrayOutputStream;
005: import java.io.DataInputStream;
006: import java.io.FileInputStream;
007: import java.io.IOException;
008: import java.lang.reflect.Method;
009: import java.net.URLConnection;
010: import java.security.KeyStore;
011: import java.security.cert.CertificateFactory;
012: import java.security.cert.X509Certificate;
013: import java.util.List;
014: import java.util.logging.Handler;
015: import java.util.logging.Level;
016: import java.util.logging.Logger;
017:
018: import javax.net.ssl.HttpsURLConnection;
019: import javax.net.ssl.KeyManager;
020: import javax.net.ssl.KeyManagerFactory;
021: import javax.net.ssl.SSLContext;
022: import javax.net.ssl.TrustManager;
023: import javax.net.ssl.TrustManagerFactory;
024:
025: import org.objectweb.celtix.bus.configuration.security.SSLClientPolicy;
026: import org.objectweb.celtix.common.logging.LogUtils;
027: import org.objectweb.celtix.configuration.Configuration;
028:
029: public final class JettySslClientConfigurer {
030: private static final long serialVersionUID = 1L;
031: private static final Logger LOG = LogUtils
032: .getL7dLogger(JettySslClientConfigurer.class);
033: private static final String DEFAUL_KEYSTORE_TYPE = "PKCS12";
034: private static final String DEFAUL_TRUST_STORE_TYPE = "JKS";
035: private static final String DEFAULT_SECURE_SOCKET_PROTOCOL = "TLSv1";
036: private static final String CERTIFICATE_FACTORY_TYPE = "X.509";
037: private static final String PKCS12_TYPE = "PKCS12";
038:
039: SSLClientPolicy sslPolicy;
040:
041: private String keyStoreLocation;
042: private String keyStorePassword;
043: private String keyPassword;
044: private String keyStoreType = DEFAUL_KEYSTORE_TYPE;
045: private String[] cipherSuites;
046: private String trustStoreLocation;
047: private String trustStoreType = DEFAUL_TRUST_STORE_TYPE;
048: private String keystoreKeyManagerFactoryAlgorithm;
049: private String trustStoreKeyManagerFactoryAlgorithm;
050: private HttpsURLConnection httpsConnection;
051: private String secureSocketProtocol;
052: private Configuration config;
053:
054: public JettySslClientConfigurer(SSLClientPolicy sslPolicyParam,
055: URLConnection connection, Configuration configurationParam) {
056:
057: this .sslPolicy = sslPolicyParam;
058: this .httpsConnection = (HttpsURLConnection) connection;
059:
060: config = configurationParam;
061:
062: }
063:
064: public void configure() {
065: setupSecurityConfigurer();
066: setupKeystore();
067: setupKeystoreType();
068: setupKeystorePassword();
069: setupKeyPassword();
070: setupKeystoreAlgorithm();
071: setupTrustStoreAlgorithm();
072: setupCiphersuites();
073: setupTrustStore();
074: setupTrustStoreType();
075: setupSecureSocketProtocol();
076: setupSessionCaching();
077: setupSessionCacheKey();
078: setupMaxChainLength();
079: setupCertValidator();
080: setupProxyHost();
081: setupProxyPort();
082:
083: if (keyStoreType.equalsIgnoreCase(PKCS12_TYPE)) {
084: setupSSLContextPKCS12();
085: } else {
086: setupSSLContext();
087: }
088:
089: }
090:
091: private boolean setupSSLContext() {
092:
093: //TODO for performance reasons we should cache the KeymanagerFactory and TrustManagerFactory
094: if ((keyStorePassword != null) && (keyPassword != null)
095: && (!keyStorePassword.equals(keyPassword))) {
096: LogUtils.log(LOG, Level.WARNING,
097: "KEY_PASSWORD_NOT_SAME_KEYSTORE_PASSWORD");
098: }
099: try {
100: SSLContext sslctx = SSLContext
101: .getInstance(secureSocketProtocol);
102:
103: KeyManagerFactory kmf = KeyManagerFactory
104: .getInstance(keystoreKeyManagerFactoryAlgorithm);
105: KeyStore ks = KeyStore.getInstance(keyStoreType);
106: FileInputStream fis = new FileInputStream(keyStoreLocation);
107: DataInputStream dis = new DataInputStream(fis);
108: byte[] bytes = new byte[dis.available()];
109: dis.readFully(bytes);
110: ByteArrayInputStream bin = new ByteArrayInputStream(bytes);
111:
112: KeyManager[] keystoreManagers = null;
113: if (keyStorePassword != null) {
114: try {
115: ks.load(bin, keyStorePassword.toCharArray());
116: kmf.init(ks, keyStorePassword.toCharArray());
117: keystoreManagers = kmf.getKeyManagers();
118: LogUtils.log(LOG, Level.INFO, "LOADED_KEYSTORE",
119: new Object[] { keyStoreLocation });
120: } catch (Exception e) {
121: LogUtils.log(LOG, Level.WARNING,
122: "FAILED_TO_LOAD_KEYSTORE", new Object[] {
123: keyStoreLocation, e.getMessage() });
124: }
125: }
126: if ((keyStorePassword == null)
127: && (keyStoreLocation != null)) {
128: LogUtils.log(LOG, Level.WARNING,
129: "FAILED_TO_LOAD_KEYSTORE_NULL_PASSWORD",
130: new Object[] { keyStoreLocation });
131: }
132:
133: // ************************* Load Trusted CA file *************************
134:
135: TrustManager[] trustStoreManagers = null;
136: KeyStore trustedCertStore = KeyStore
137: .getInstance(trustStoreType);
138:
139: trustedCertStore.load(new FileInputStream(
140: trustStoreLocation), null);
141: TrustManagerFactory tmf = TrustManagerFactory
142: .getInstance(trustStoreKeyManagerFactoryAlgorithm);
143: try {
144: tmf.init(trustedCertStore);
145: trustStoreManagers = tmf.getTrustManagers();
146: LogUtils.log(LOG, Level.INFO, "LOADED_TRUST_STORE",
147: new Object[] { trustStoreLocation });
148: } catch (Exception e) {
149: LogUtils.log(LOG, Level.WARNING,
150: "FAILED_TO_LOAD_TRUST_STORE", new Object[] {
151: trustStoreLocation, e.getMessage() });
152: }
153: sslctx.init(keystoreManagers, trustStoreManagers, null);
154:
155: httpsConnection
156: .setSSLSocketFactory(new SSLSocketFactoryWrapper(
157: sslctx.getSocketFactory(), cipherSuites));
158:
159: } catch (Exception e) {
160: LogUtils.log(LOG, Level.SEVERE, "SSL_CONTEXT_INIT_FAILURE",
161: new Object[] { e.getMessage() });
162: return false;
163: }
164: return true;
165: }
166:
167: private boolean setupSSLContextPKCS12() {
168:
169: //TODO for performance reasons we should cache the KeymanagerFactory and TrustManagerFactory
170: if ((keyStorePassword != null) && (keyPassword != null)
171: && (!keyStorePassword.equals(keyPassword))) {
172: LogUtils.log(LOG, Level.WARNING,
173: "KEY_PASSWORD_NOT_SAME_KEYSTORE_PASSWORD");
174: }
175: try {
176: SSLContext sslctx = SSLContext
177: .getInstance(secureSocketProtocol);
178: KeyManagerFactory kmf = KeyManagerFactory
179: .getInstance(keystoreKeyManagerFactoryAlgorithm);
180: KeyStore ks = KeyStore.getInstance(keyStoreType);
181: KeyManager[] keystoreManagers = null;
182:
183: byte[] sslCert = loadClientCredential(keyStoreLocation);
184:
185: if (sslCert != null && sslCert.length > 0
186: && keyStorePassword != null) {
187: ByteArrayInputStream bin = new ByteArrayInputStream(
188: sslCert);
189: try {
190: ks.load(bin, keyStorePassword.toCharArray());
191: kmf.init(ks, keyStorePassword.toCharArray());
192: keystoreManagers = kmf.getKeyManagers();
193: LogUtils.log(LOG, Level.INFO, "LOADED_KEYSTORE",
194: new Object[] { keyStoreLocation });
195: } catch (Exception e) {
196: LogUtils.log(LOG, Level.WARNING,
197: "FAILED_TO_LOAD_KEYSTORE", new Object[] {
198: keyStoreLocation, e.getMessage() });
199: }
200: }
201: if ((keyStorePassword == null)
202: && (keyStoreLocation != null)) {
203: LogUtils.log(LOG, Level.WARNING,
204: "FAILED_TO_LOAD_KEYSTORE_NULL_PASSWORD",
205: new Object[] { keyStoreLocation });
206: }
207:
208: // ************************* Load Trusted CA file *************************
209: //TODO could support multiple trust cas
210: TrustManager[] trustStoreManagers = new TrustManager[1];
211:
212: KeyStore trustedCertStore = KeyStore
213: .getInstance(trustStoreType);
214: trustedCertStore.load(null, "".toCharArray());
215: CertificateFactory cf = CertificateFactory
216: .getInstance(CERTIFICATE_FACTORY_TYPE);
217: byte[] caCert = loadCACert(trustStoreLocation);
218: try {
219: if (caCert != null) {
220: ByteArrayInputStream cabin = new ByteArrayInputStream(
221: caCert);
222: X509Certificate cert = (X509Certificate) cf
223: .generateCertificate(cabin);
224: trustedCertStore.setCertificateEntry(cert
225: .getIssuerDN().toString(), cert);
226: cabin.close();
227: }
228: } catch (Exception e) {
229: LogUtils.log(LOG, Level.WARNING,
230: "FAILED_TO_LOAD_TRUST_STORE", new Object[] {
231: trustStoreLocation, e.getMessage() });
232: }
233: TrustManagerFactory tmf = TrustManagerFactory
234: .getInstance(trustStoreKeyManagerFactoryAlgorithm);
235:
236: tmf.init(trustedCertStore);
237: LogUtils.log(LOG, Level.INFO, "LOADED_TRUST_STORE",
238: new Object[] { trustStoreLocation });
239:
240: trustStoreManagers = tmf.getTrustManagers();
241:
242: sslctx.init(keystoreManagers, trustStoreManagers, null);
243: httpsConnection
244: .setSSLSocketFactory(new SSLSocketFactoryWrapper(
245: sslctx.getSocketFactory(), cipherSuites));
246:
247: } catch (Exception e) {
248: LogUtils.log(LOG, Level.SEVERE, "SSL_CONTEXT_INIT_FAILURE",
249: new Object[] { e.getMessage() });
250: return false;
251: }
252: return true;
253: }
254:
255: private static byte[] loadClientCredential(String fileName)
256: throws IOException {
257: if (fileName == null) {
258: return null;
259: }
260: FileInputStream in = new FileInputStream(fileName);
261: ByteArrayOutputStream out = new ByteArrayOutputStream();
262: byte[] buf = new byte[512];
263: int i = in.read(buf);
264: while (i > 0) {
265: out.write(buf, 0, i);
266: i = in.read(buf);
267: }
268: in.close();
269: return out.toByteArray();
270: }
271:
272: private static byte[] loadCACert(String fileName)
273: throws IOException {
274: if (fileName == null) {
275: return null;
276: }
277: FileInputStream in = new FileInputStream(fileName);
278: ByteArrayOutputStream out = new ByteArrayOutputStream();
279: byte[] buf = new byte[512];
280: int i = in.read(buf);
281:
282: while (i > 0) {
283: out.write(buf, 0, i);
284: i = in.read(buf);
285: }
286: in.close();
287: return out.toByteArray();
288: }
289:
290: public void setupKeystore() {
291: if (sslPolicy.isSetKeystore()) {
292: keyStoreLocation = sslPolicy.getKeystore();
293: LogUtils.log(LOG, Level.INFO, "KEY_STORE_SET",
294: new Object[] { keyStoreLocation });
295: return;
296: }
297: keyStoreLocation = System.getProperty("javax.net.ssl.keyStore");
298: if (keyStoreLocation != null) {
299: LogUtils.log(LOG, Level.INFO,
300: "KEY_STORE_SYSTEM_PROPERTY_SET",
301: new Object[] { keyStoreLocation });
302: return;
303: }
304:
305: keyStoreLocation = System.getProperty("user.home")
306: + "/.keystore";
307: LogUtils.log(LOG, Level.INFO, "KEY_STORE_NOT_SET",
308: new Object[] { keyStoreLocation });
309:
310: }
311:
312: public void setupKeystoreType() {
313: if (!sslPolicy.isSetKeystoreType()) {
314: LogUtils.log(LOG, Level.INFO, "KEY_STORE_TYPE_NOT_SET",
315: new Object[] { DEFAUL_KEYSTORE_TYPE });
316: return;
317: }
318: keyStoreType = sslPolicy.getKeystoreType();
319: LogUtils.log(LOG, Level.INFO, "KEY_STORE_TYPE_SET",
320: new Object[] { keyStoreType });
321: }
322:
323: public void setupKeystorePassword() {
324: if (sslPolicy.isSetKeystorePassword()) {
325: LogUtils.log(LOG, Level.INFO, "KEY_STORE_PASSWORD_SET");
326: keyStorePassword = sslPolicy.getKeystorePassword();
327: return;
328: }
329: keyStorePassword = System
330: .getProperty("javax.net.ssl.keyStorePassword");
331: if (keyStorePassword != null) {
332: LogUtils.log(LOG, Level.INFO,
333: "KEY_STORE_PASSWORD_SYSTEM_PROPERTY_SET");
334: return;
335: }
336: LogUtils.log(LOG, Level.INFO, "KEY_STORE_PASSWORD_NOT_SET");
337:
338: }
339:
340: public void setupKeyPassword() {
341: if (sslPolicy.isSetKeyPassword()) {
342: LogUtils.log(LOG, Level.INFO, "KEY_PASSWORD_SET");
343: keyPassword = sslPolicy.getKeyPassword();
344: return;
345: }
346: keyPassword = System
347: .getProperty("javax.net.ssl.keyStorePassword");
348: if (keyPassword != null) {
349: LogUtils.log(LOG, Level.INFO,
350: "KEY_PASSWORD_SYSTEM_PROPERTY_SET");
351: return;
352: }
353:
354: LogUtils.log(LOG, Level.INFO, "KEY_PASSWORD_NOT_SET");
355: }
356:
357: public void setupKeystoreAlgorithm() {
358: if (sslPolicy.isSetKeystoreAlgorithm()) {
359: keystoreKeyManagerFactoryAlgorithm = sslPolicy
360: .getKeystoreAlgorithm();
361: LogUtils
362: .log(
363: LOG,
364: Level.INFO,
365: "KEY_STORE_ALGORITHM_SET",
366: new Object[] { keystoreKeyManagerFactoryAlgorithm });
367: return;
368: }
369: keystoreKeyManagerFactoryAlgorithm = KeyManagerFactory
370: .getDefaultAlgorithm();
371: LogUtils.log(LOG, Level.INFO, "KEY_STORE_ALGORITHM_NOT_SET",
372: new Object[] { keystoreKeyManagerFactoryAlgorithm });
373: }
374:
375: public void setupTrustStoreAlgorithm() {
376: if (sslPolicy.isSetKeystoreAlgorithm()) {
377: trustStoreKeyManagerFactoryAlgorithm = sslPolicy
378: .getTrustStoreAlgorithm();
379: LogUtils
380: .log(
381: LOG,
382: Level.INFO,
383: "TRUST_STORE_ALGORITHM_SET",
384: new Object[] { trustStoreKeyManagerFactoryAlgorithm });
385: return;
386: }
387: trustStoreKeyManagerFactoryAlgorithm = TrustManagerFactory
388: .getDefaultAlgorithm();
389: LogUtils.log(LOG, Level.INFO, "TRUST_STORE_ALGORITHM_NOT_SET",
390: new Object[] { trustStoreKeyManagerFactoryAlgorithm });
391: }
392:
393: public void setupCiphersuites() {
394: if (sslPolicy.isSetCiphersuites()) {
395:
396: List<String> cipherSuitesList = sslPolicy.getCiphersuites();
397: int numCipherSuites = cipherSuitesList.size();
398: cipherSuites = new String[numCipherSuites];
399: String ciphsStr = null;
400: for (int i = 0; i < numCipherSuites; i++) {
401: cipherSuites[i] = cipherSuitesList.get(i);
402: if (ciphsStr == null) {
403: ciphsStr = cipherSuites[i];
404: } else {
405: ciphsStr += ", " + cipherSuites[i];
406: }
407: }
408: LogUtils.log(LOG, Level.INFO, "CIPHERSUITE_SET",
409: new Object[] { ciphsStr });
410: return;
411: }
412: LogUtils.log(LOG, Level.INFO, "CIPHERSUITE_NOT_SET");
413: }
414:
415: public void setupTrustStore() {
416: if (sslPolicy.isSetTrustStore()) {
417: trustStoreLocation = sslPolicy.getTrustStore();
418: LogUtils.log(LOG, Level.INFO, "TRUST_STORE_SET",
419: new Object[] { trustStoreLocation });
420: return;
421: }
422:
423: trustStoreLocation = System
424: .getProperty("javax.net.ssl.trustStore");
425: if (trustStoreLocation != null) {
426: LogUtils.log(LOG, Level.INFO,
427: "TRUST_STORE_SYSTEM_PROPERTY_SET",
428: new Object[] { trustStoreLocation });
429: return;
430: }
431:
432: trustStoreLocation = System.getProperty("java.home")
433: + "/lib/security/cacerts";
434: LogUtils.log(LOG, Level.INFO, "TRUST_STORE_NOT_SET",
435: new Object[] { trustStoreLocation });
436:
437: }
438:
439: public void setupTrustStoreType() {
440: if (!sslPolicy.isSetTrustStoreType()) {
441: LogUtils.log(LOG, Level.INFO, "TRUST_STORE_TYPE_NOT_SET",
442: new Object[] { DEFAUL_TRUST_STORE_TYPE });
443: //Can default to JKS so return
444: return;
445: }
446: trustStoreType = sslPolicy.getTrustStoreType();
447: LogUtils.log(LOG, Level.INFO, "TRUST_STORE_TYPE_SET",
448: new Object[] { trustStoreType });
449: }
450:
451: public void setupSecureSocketProtocol() {
452: if (!sslPolicy.isSetSecureSocketProtocol()) {
453: LogUtils.log(LOG, Level.INFO,
454: "SECURE_SOCKET_PROTOCOL_NOT_SET");
455: secureSocketProtocol = DEFAULT_SECURE_SOCKET_PROTOCOL;
456: return;
457: }
458: secureSocketProtocol = sslPolicy.getSecureSocketProtocol();
459: LogUtils.log(LOG, Level.INFO, "SECURE_SOCKET_PROTOCOL_SET",
460: new Object[] { secureSocketProtocol });
461: }
462:
463: public boolean setupSessionCaching() {
464: if (sslPolicy.isSetSessionCaching()) {
465: LogUtils.log(LOG, Level.WARNING,
466: "UNSUPPORTED_SSL_CLIENT_POLICY_DATA",
467: new Object[] { "SessionCaching" });
468: }
469: return true;
470: }
471:
472: public boolean setupSessionCacheKey() {
473: if (sslPolicy.isSetSessionCacheKey()) {
474: LogUtils.log(LOG, Level.WARNING,
475: "UNSUPPORTED_SSL_CLIENT_POLICY_DATA",
476: new Object[] { "SessionCacheKey" });
477: }
478: return true;
479: }
480:
481: public boolean setupMaxChainLength() {
482: if (sslPolicy.isSetMaxChainLength()) {
483: LogUtils.log(LOG, Level.WARNING,
484: "UNSUPPORTED_SSL_CLIENT_POLICY_DATA",
485: new Object[] { "MaxChainLength" });
486: }
487: return true;
488: }
489:
490: public boolean setupCertValidator() {
491: if (sslPolicy.isSetCertValidator()) {
492: LogUtils.log(LOG, Level.WARNING,
493: "UNSUPPORTED_SSL_CLIENT_POLICY_DATA",
494: new Object[] { "CertValidator" });
495: }
496: return true;
497: }
498:
499: public boolean setupProxyHost() {
500: if (sslPolicy.isSetProxyHost()) {
501: LogUtils.log(LOG, Level.WARNING,
502: "UNSUPPORTED_SSL_CLIENT_POLICY_DATA",
503: new Object[] { "ProxyHost" });
504: }
505: return true;
506: }
507:
508: public boolean setupProxyPort() {
509: if (sslPolicy.isSetProxyPort()) {
510: LogUtils.log(LOG, Level.WARNING,
511: "UNSUPPORTED_SSL_CLIENT_POLICY_DATA",
512: new Object[] { "ProxyPort" });
513: }
514: return true;
515: }
516:
517: public void setupSecurityConfigurer() {
518: String systemProperty = "celtix.security.configurer.celtix."
519: + config.getId() + ".http-client";
520: String securityConfigurerName = System
521: .getProperty(systemProperty);
522:
523: if ((securityConfigurerName == null)
524: || (securityConfigurerName.equals(""))) {
525: return;
526: }
527: LogUtils.log(LOG, Level.WARNING,
528: "UNOFFICIAL_SECURITY_CONFIGURER");
529:
530: try {
531: Class clazz = Class.forName(securityConfigurerName);
532: Method configure = clazz.getDeclaredMethod("configure",
533: SSLClientPolicy.class);
534: Object[] params = new Object[] { sslPolicy };
535: Object configurer = clazz.newInstance();
536: configure.invoke(configurer, params);
537: LogUtils.log(LOG, Level.INFO,
538: "SUCCESS_INVOKING_SECURITY_CONFIGURER",
539: new Object[] { securityConfigurerName });
540: } catch (Exception e) {
541: LogUtils.log(LOG, Level.SEVERE,
542: "ERROR_INVOKING_SECURITY_CONFIGURER", new Object[] {
543: securityConfigurerName, e.getMessage() });
544: }
545: }
546:
547: protected HttpsURLConnection getHttpsConnection() {
548: return httpsConnection;
549: }
550:
551: /*
552: * For development and testing only
553: */
554:
555: protected boolean testAllDataHasSetupMethod() {
556: Method[] sslPolicyMethods = sslPolicy.getClass()
557: .getDeclaredMethods();
558: Class[] classArgs = null;
559:
560: for (int i = 0; i < sslPolicyMethods.length; i++) {
561: String sslPolicyMethodName = sslPolicyMethods[i].getName();
562: if (sslPolicyMethodName.startsWith("isSet")) {
563: String dataName = sslPolicyMethodName.substring("isSet"
564: .length(), sslPolicyMethodName.length());
565: String this MethodName = "setup" + dataName;
566: try {
567: this .getClass()
568: .getMethod(this MethodName, classArgs);
569: } catch (Exception e) {
570: e.printStackTrace();
571: return false;
572: }
573:
574: }
575: }
576: return true;
577: }
578:
579: protected void addLogHandler(Handler handler) {
580: LOG.addHandler(handler);
581: }
582:
583: }
|