package com.grendelscan.commons.http.ssl;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.scheme.SchemeSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
/**
* Basically a modified version of org.apache.http.conn.ssl.SSLSocketFactory
*
* @author David Byrne
*
*/
public class CustomSSLSocketFactory implements SchemeSocketFactory
{
private X509HostnameVerifier hostnameVerifier = new CustomSSLVerifier();
private final javax.net.ssl.SSLSocketFactory socketfactory;
private final SSLContext sslcontext;
public CustomSSLSocketFactory() throws NoSuchAlgorithmException, KeyManagementException
{
SecureRandom random = new SecureRandom();
TrustManager[] trustmanagers = null;
trustmanagers = createTrustManagers();
sslcontext = SSLContext.getInstance("TLS");
sslcontext.init(null, trustmanagers, random);
socketfactory = sslcontext.getSocketFactory();
}
/*
* (non-Javadoc)
*
* @see org.apache.http.conn.scheme.SchemeSocketFactory#connectSocket(java.net.Socket, java.net.InetSocketAddress, java.net.InetSocketAddress, org.apache.http.params.HttpParams)
*/
@Override
public Socket connectSocket(final Socket sock, final InetSocketAddress remoteAddress, final InetSocketAddress localAddress, final HttpParams params) throws IOException, UnknownHostException, ConnectTimeoutException
// public Socket connectSocket(final Socket sock, final String host, final int port, final InetAddress localAddress,
// int localPort, final HttpParams params) throws IOException
{
String host = remoteAddress.getHostName();
// if (host == null)
// {
// throw new IllegalArgumentException("Target host may not be null.");
// }
if (params == null)
{
throw new IllegalArgumentException("Parameters may not be null.");
}
// resolve the target hostname first
// final InetSocketAddress target = new InetSocketAddress(host, port);
SSLSocket sslSocket = (SSLSocket) (sock != null ? sock : createSocket(params));
if (localAddress != null)
{
// // we need to bind explicitly
// if (localPort < 0)
// {
// localPort = 0; // indicates "any"
// }
// InetSocketAddress isa = new InetSocketAddress(localAddress, localPort);
sslSocket.bind(localAddress);
}
int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
int soTimeout = HttpConnectionParams.getSoTimeout(params);
sslSocket.connect(remoteAddress, connTimeout);
sslSocket.setSoTimeout(soTimeout);
try
{
hostnameVerifier.verify(host, sslSocket);
// verifyHostName() didn't blowup - good!
}
catch (IOException iox)
{
// close the socket before re-throwing the exception
try
{
sslSocket.close();
}
catch (Exception x)
{ /* ignore */
}
throw iox;
}
return sslSocket;
}
/*
* (non-Javadoc)
*
* @see org.apache.http.conn.scheme.SchemeSocketFactory#createSocket(org.apache.http.params.HttpParams)
*/
@Override
public Socket createSocket(final HttpParams params) throws IOException
{
return socketfactory.createSocket();
}
// // non-javadoc, see interface org.apache.http.conn.SocketFactory
// @Override
// public Socket createSocket() throws IOException
// {
//
// // the cast makes sure that the factory is working as expected
//
// }
//
// // non-javadoc, see interface LayeredSocketFactory
// @Override
// public Socket createSocket(final Socket socket, final String host, final int port, final boolean autoClose)
// throws IOException, UnknownHostException
// {
// SSLSocket sslSocket = (SSLSocket) socketfactory.createSocket(socket, host, port, autoClose);
// hostnameVerifier.verify(host, sslSocket);
// // verifyHostName() didn't blowup - good!
// return sslSocket;
// }
private TrustManager[] createTrustManagers()
{
TrustManager tms[] = { new CustomX509TrustManager() };
return tms;
}
public HostnameVerifier getHostnameVerifier()
{
return hostnameVerifier;
}
/**
* Checks whether a socket connection is secure. This factory creates TLS/SSL socket connections which, by default, are considered secure. <br/>
* Derived classes may override this method to perform runtime checks, for example based on the cypher suite.
*
* @param sock
* the connected socket
*
* @return <code>true</code>
*
* @throws IllegalArgumentException
* if the argument is invalid
*/
@Override
public boolean isSecure(final Socket sock) throws IllegalArgumentException
{
if (sock == null)
{
throw new IllegalArgumentException("Socket may not be null.");
}
// This instanceof check is in line with createSocket() above.
if (!(sock instanceof SSLSocket))
{
throw new IllegalArgumentException("Socket not created by this factory.");
}
// This check is performed last since it calls the argument object.
if (sock.isClosed())
{
throw new IllegalArgumentException("Socket is closed.");
}
return true;
} // isSecure
public void setHostnameVerifier(final X509HostnameVerifier hostnameVerifier)
{
if (hostnameVerifier == null)
{
throw new IllegalArgumentException("Hostname verifier may not be null");
}
this.hostnameVerifier = hostnameVerifier;
}
}