よい子がまねしちゃいけない、HttpClient-4.0の使い方(SSL編)
ちょっと前の話ですが、commons-HttpClientがApache-HttpComponentsの一部となりました。バージョンも3から4に上がり、クラス構成も変わったみたいです。3.0のころのHttpClientは割とネットに情報が多く、何をやるにも困りませんでした。でも4.0以降になるとあんまりないんです。
今回、「サーバの証明書なしに、HttpClientでSSLを使う」ということをやってみました。これもHttpClient-3.0だとググれば情報がありますが、4.0系だとそのままは使えないようで、コピペ厨にとっては問題です。
まずはSSLSocketFactoryに手を加えたもの。
import java.io.IOException; import java.net.Socket; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; import javax.net.ssl.SSLContext; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import org.apache.http.conn.scheme.HostNameResolver; import org.apache.http.conn.ssl.SSLSocketFactory; public class NoneSSLVerifierSSLSocketFactory extends SSLSocketFactory { private final SSLContext sslcontext; public NoneSSLVerifierSSLSocketFactory(final SSLContext sslContext, final HostNameResolver nameResolver) { super(sslContext, nameResolver); sslcontext = sslContext; } public static NoneSSLVerifierSSLSocketFactory create() throws NoSuchAlgorithmException, KeyManagementException { SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, new TrustManager[] { new X509TrustManager() { @Override public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { } @Override public X509Certificate[] getAcceptedIssuers() { return null; } } }, null); return new NoneSSLVerifierSSLSocketFactory(sslContext, null); } @Override public Socket createSocket() throws IOException { return sslcontext.getSocketFactory().createSocket(); } }
そして、手を加えたSSLSocketFactoryを使用する、HttpClient。
import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import org.apache.http.client.params.ClientPNames; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.conn.ClientConnectionManagerFactory; import org.apache.http.conn.scheme.PlainSocketFactory; import org.apache.http.conn.scheme.Scheme; import org.apache.http.conn.scheme.SchemeRegistry; import org.apache.http.conn.ssl.SSLSocketFactory; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.impl.conn.SingleClientConnManager; import org.apache.http.params.HttpParams; public class NoneSSLVerifierHttpClient extends DefaultHttpClient { @Override protected ClientConnectionManager createClientConnectionManager() { SchemeRegistry registry = new SchemeRegistry(); registry.register(new Scheme("http", PlainSocketFactory .getSocketFactory(), 80)); SSLSocketFactory sslSocketFactory = null; try { sslSocketFactory = NoneSSLVerifierSSLSocketFactory.create(); } catch (KeyManagementException e) { throw new RuntimeException(e); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } sslSocketFactory.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); registry.register(new Scheme("https", sslSocketFactory, 443)); ClientConnectionManager connManager = null; HttpParams params = getParams(); ClientConnectionManagerFactory factory = null; String className = (String) params .getParameter(ClientPNames.CONNECTION_MANAGER_FACTORY_CLASS_NAME); if (className != null) { try { Class<?> clazz = Class.forName(className); factory = (ClientConnectionManagerFactory) clazz.newInstance(); } catch (ClassNotFoundException ex) { throw new IllegalStateException("Invalid class name: " + className); } catch (IllegalAccessException ex) { throw new IllegalAccessError(ex.getMessage()); } catch (InstantiationException ex) { throw new InstantiationError(ex.getMessage()); } } if (factory != null) { connManager = factory.newInstance(params, registry); } else { connManager = new SingleClientConnManager(getParams(), registry); } return connManager; } }
あとはNoneSSLVerifierHttpClient を使うだけ。でもこれ。どう考えても危険なので、インターネット上のアプリケーションには使用しないことをおすすめします。痛い目見る可能性有りです。
よい子はちゃんとkeytoolを使って、証明書を登録してやりましょう。