/*
* Copyright (c) 2009 EMC Corporation
* All Rights Reserved
*/
package com.emc.cloud.http.ssl;
import com.emc.storageos.coordinator.client.service.CoordinatorClient;
import com.emc.storageos.security.ssl.ViPRX509TrustManager;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.AbstractHttpClient;
//import java.util.Properties;
/**
* Helper for configuring SSL connections
*
* @author perkib
*/
public class SSLHelper {
/**
* static only, no instances!
*/
private SSLHelper() {
}
/**
* Set the necessary options on an HttpClient instance to enable permissive
* SSL connections. This implies disabling of trust validation, hostname
* verification, and expiration checks.
* <p>
* WARNING: This is very handy for development and testing, but is NOT recommended for production code.
* <p>
*
* @param httpClient
* An HttpClient instance to be configured
* @throws IllegalArgumentException
* if the argument is null
* @throws GeneralSecurityException
* if an error occurs in changing the SSL settings
*/
public static void configurePermissiveSSL(AbstractHttpClient httpClient)
throws GeneralSecurityException {
if (httpClient == null) {
throw new IllegalArgumentException(
"null httpClient argument is not allowed");
}
// make https validation extremely permissive/insecure by disabling
// checks for trusted certificates & host name validation
SSLContext sslContext;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[] { new PermissiveX509TrustManager(null) }, null);
SSLSocketFactory socketFactory = new SupportedSSLSocketFactory(sslContext);
socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
// replace the default https scheme with our own
Scheme sch = new Scheme("https", socketFactory, 443);
httpClient.getConnectionManager().getSchemeRegistry().register(sch);
} catch (GeneralSecurityException ex) {
throw new GeneralSecurityException(
"Error updating https scheme with permissive settings", ex);
}
}
public static void configureSSLWithTrustManger(AbstractHttpClient httpClient, CoordinatorClient coordinatorClient)
throws GeneralSecurityException {
if (httpClient == null || coordinatorClient == null) {
if (httpClient == null) {
throw new IllegalArgumentException(
"null httpClient argument is not allowed");
}
throw new IllegalArgumentException(
"null coordinatorClient is not allowed");
}
SSLContext sslContext;
try {
sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, new TrustManager[] { new ViPRX509TrustManager(coordinatorClient) }, null);
SSLSocketFactory socketFactory = new SupportedSSLSocketFactory(sslContext);
socketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
Scheme sch = new Scheme("https", socketFactory, 443);
httpClient.getConnectionManager().getSchemeRegistry().register(sch);
} catch (GeneralSecurityException ex) {
throw new GeneralSecurityException(
"Error updating https scheme with trust manager", ex);
}
}
public static class SupportedSSLSocketFactory extends SSLSocketFactory {
public SupportedSSLSocketFactory(SSLContext sslContext) {
super(sslContext);
}
@Override
public Socket createSocket() throws IOException {
Socket socket = super.createSocket();
return enableProtocols(socket);
}
@Override
public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException {
Socket newSocket = super.createSocket(socket, host, port, autoClose);
return enableProtocols(newSocket);
}
/**
* If the socket is an SSLSocket, set the list of accepted protocols.
*
* @param socket
* @return
*/
private Socket enableProtocols(Socket socket) {
if (socket instanceof SSLSocket) {
SSLSocket sslSocket = (SSLSocket) socket;
ArrayList<String> protocols = new ArrayList<String>();
for (String protocol : sslSocket.getEnabledProtocols()) {
if (!protocol.startsWith(SSLV2)) {
protocols.add(protocol);
}
}
sslSocket.setEnabledProtocols((String[]) protocols.toArray(new String[protocols.size()]));
}
return socket;
}
}
}