/*******************************************************************************
* Copyright 2015 Miami-Dade County
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package org.sharegov.cirm;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import org.apache.commons.httpclient.protocol.ProtocolSocketFactory;
import org.sharegov.cirm.utils.SslContextedSecureProtocolSocketFactory;
/**
* Utilities for starting embedded web servers.
*
* @author Thomas Hilpold
*
*/
public class StartupUtils
{
/**
* Gets all supported cipher suites that are considered strong as String.
*
* @return space separated String
*/
static String getStrongSSLCipherSuitesParamString() {
return getListAsParamString(getStrongSSLCipherSuites());
}
/**
* Gets all supported cipher suites that are considered weak as String.
*
* @return space separated String
*/
static String getWeakSSLCipherSuitesParamString() {
return getListAsParamString(getWeakSSLCipherSuites());
}
/**
* Converts a list of Strings into a single space separated string.
*
* @param stringList a list of strings
* @return a single line string containing list items separared by spaces.
*/
static String getListAsParamString(List<String> stringList) {
StringBuffer result = new StringBuffer(1000);
Iterator<String> cipherIt = stringList.iterator();
while(cipherIt.hasNext()) {
result.append(cipherIt.next());
if (cipherIt.hasNext()) result.append(" ");
}
return result.toString();
}
/**
* Gets a list of all supported cipher suites that are considered strong.
*/
static List<String> getStrongSSLCipherSuites() {
List<String> strongCiphers = new LinkedList<>();
for (String cipher : getSupportedCipherSuites()) {
if (cipher.startsWith("TLS_DHE_RSA") || cipher.startsWith("TLS_ECDHE")) {
strongCiphers.add(cipher);
System.out.println(cipher);
}
}
return strongCiphers;
}
/**
* Gets a list of all supported cipher suites that are considered weak.
*/
static List<String> getWeakSSLCipherSuites() {
List<String> weakCiphers = new LinkedList<>();
for (String cipher : getSupportedCipherSuites()) {
if (cipher.contains("NULL")
|| cipher.contains("RC4")
|| cipher.contains("MD5")
|| cipher.contains("DES")
|| cipher.contains("DSS")
) {
weakCiphers.add(cipher);
}
}
return weakCiphers;
}
/**
* Gets all supported cipher suites in the java runtime.
* Note that this depends on secuity policy and java version.
*
* @return supported ciphers as sorted set of strings.
*/
static SortedSet<String> getSupportedCipherSuites() {
SSLContext ctx;
try
{
ctx = SSLContext.getDefault();
} catch (NoSuchAlgorithmException e)
{
throw new RuntimeException(e);
}
SSLSocketFactory sf = ctx.getSocketFactory();
return new TreeSet<>(Arrays.asList(sf.getSupportedCipherSuites()));
}
/**
* Prints all
*/
static void printSSLCipherSuites() {
SSLContext ctx;
try
{
ctx = SSLContext.getDefault();
} catch (NoSuchAlgorithmException e)
{
throw new RuntimeException(e);
}
SSLSocketFactory sf = ctx.getSocketFactory();
SortedSet<String> defaultCiphers = new TreeSet<>(Arrays.asList(sf.getDefaultCipherSuites()));
SortedSet<String> supportedCiphers = new TreeSet<>(Arrays.asList(sf.getSupportedCipherSuites()));
System.out.println("DEFAULT CIPHERS");
for (String c : defaultCiphers) {
System.out.println(c);
}
System.out.println("SUPPORTED CIPHERS");
for (String c : supportedCiphers) {
System.out.println(c);
}
}
/**
* Installs a Trustmanager for TLS HttpsURLConnection and apache commons https clients that accepts all certificates
* and does not validate server names.
*
* DO NOT USE IN PRODUCTION.
*/
public static void disableCertificateValidation()
{
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager()
{
public X509Certificate[] getAcceptedIssuers()
{
return new X509Certificate[0];
}
public void checkClientTrusted(X509Certificate[] certs,
String authType)
{}
public void checkServerTrusted(X509Certificate[] certs,
String authType)
{}
} };
// Ignore differences between given hostname and certificate hostname
HostnameVerifier hv = new HostnameVerifier()
{
@Override
public boolean verify(String hostname, SSLSession session)
{
return true;
}
};
// Install the all-trusting trust manager
try
{
SSLContext ctx = SSLContext.getInstance("TLSv1.2");
ctx.init(new KeyManager[0], trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(ctx
.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(hv);
// see:http://stackoverflow.com/questions/1828775/how-to-handle-invalid-ssl-certificates-with-apache-httpclient
// see:https://code.google.com/p/jsslutils/wiki/ApacheHttpClientUsage
org.apache.commons.httpclient.protocol.Protocol
.registerProtocol(
"https",
new org.apache.commons.httpclient.protocol.Protocol(
"https",
(ProtocolSocketFactory) new SslContextedSecureProtocolSocketFactory(
ctx, false), 443));
SSLContext.setDefault(ctx);
}
catch (Exception e)
{
}
}
}