/* * Copyright 2009 NCHOVY * * 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.krakenapps.pkg; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.Socket; import java.net.URL; import java.net.UnknownHostException; import java.nio.charset.Charset; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.net.ssl.HandshakeCompletedEvent; import javax.net.ssl.HandshakeCompletedListener; import javax.net.ssl.KeyManager; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import org.apache.commons.httpclient.ConnectTimeoutException; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.params.HttpConnectionParams; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.commons.httpclient.protocol.Protocol; import org.apache.commons.httpclient.protocol.ProtocolSocketFactory; import org.apache.commons.httpclient.protocol.SecureProtocolSocketFactory; import org.krakenapps.confdb.Config; import org.krakenapps.confdb.ConfigDatabase; import org.krakenapps.confdb.ConfigService; import org.krakenapps.main.Kraken; import org.osgi.framework.ServiceReference; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class HttpWagon { private HttpWagon() { } public static String downloadString(URL url) throws IOException { return downloadString(url, false, null, null); } public static String downloadString(URL url, String username, String password) throws IOException { return downloadString(url, true, username, password); } private static String downloadString(URL url, boolean useAuth, String username, String password) throws IOException { byte[] responseBody = download(url, useAuth, username, password); return new String(responseBody, Charset.forName("utf-8")); } public static byte[] download(URL url) throws IOException { return download(url, false, null, null); } public static InputStream openDownloadStream(URL url) throws IOException { return openDownloadStream(url, false, null, null); } public static byte[] download(URL url, TrustManagerFactory tmf, KeyManagerFactory kmf) throws KeyManagementException, IOException { ByteArrayOutputStream os = new ByteArrayOutputStream(); InputStream is = openDownloadStream(url, tmf, kmf); try { byte[] b = new byte[8096]; while (true) { int read = is.read(b); if (read <= 0) break; os.write(b, 0, read); } return os.toByteArray(); } finally { is.close(); } } public static InputStream openDownloadStream(URL url, TrustManagerFactory tmf, KeyManagerFactory kmf) throws KeyManagementException, IOException { SSLContext ctx = null; try { ctx = SSLContext.getInstance("SSL"); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } TrustManager[] trustManagers = null; KeyManager[] keyManagers = null; if (tmf != null) trustManagers = tmf.getTrustManagers(); if (kmf != null) keyManagers = kmf.getKeyManagers(); ctx.init(keyManagers, trustManagers, new SecureRandom()); HttpsSocketFactory h = new HttpsSocketFactory(kmf, tmf); Protocol https = new Protocol("https", (ProtocolSocketFactory) h, 443); Protocol.registerProtocol("https", https); HttpClient client = new HttpClient(); HttpMethod method = new GetMethod(url.toString()); client.executeMethod(method); return method.getResponseBodyAsStream(); } public static byte[] download(URL url, boolean useAuth, String username, String password) throws IOException { ByteArrayOutputStream os = new ByteArrayOutputStream(); InputStream is = openDownloadStream(url, useAuth, username, password); try { byte[] b = new byte[8096]; while (true) { int read = is.read(b); if (read <= 0) break; os.write(b, 0, read); } return os.toByteArray(); } finally { is.close(); } } public static InputStream openDownloadStream(URL url, boolean useAuth, String username, String password) throws IOException { Logger logger = LoggerFactory.getLogger(HttpWagon.class.getName()); logger.trace("http wagon: downloading {}", url); HttpClient client = new HttpClient(); if (useAuth) { client.getParams().setAuthenticationPreemptive(true); Credentials defaultcreds = new UsernamePasswordCredentials(username, password); client.getState().setCredentials(new AuthScope(url.getHost(), url.getPort(), AuthScope.ANY_REALM), defaultcreds); } HttpMethod method = new GetMethod(url.toString()); int socketTimeout = getSocketTimeout(); int connectionTimeout = getConnectTimeout(); client.getParams().setParameter("http.socket.timeout", socketTimeout); client.getParams().setParameter("http.connection.timeout", connectionTimeout); client.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, null); int statusCode = client.executeMethod(method); if (statusCode != HttpStatus.SC_OK) { throw new IOException("method failed: " + method.getStatusLine()); } return method.getResponseBodyAsStream(); } private static int getSocketTimeout() { ServiceReference ref = Kraken.getContext().getServiceReference(ConfigService.class.getName()); if (ref != null) { ConfigService conf = (ConfigService) Kraken.getContext().getService(ref); ConfigDatabase db = conf.ensureDatabase("kraken-core"); Config c = db.findOne(HttpWagonConfig.class, null); if (c != null) { HttpWagonConfig hc = c.getDocument(HttpWagonConfig.class); return hc.getReadTimeout(); } } return 10000; } private static int getConnectTimeout() { ServiceReference ref = Kraken.getContext().getServiceReference(ConfigService.class.getName()); if (ref != null) { ConfigService conf = (ConfigService) Kraken.getContext().getService(ref); ConfigDatabase db = conf.ensureDatabase("kraken-core"); Config c = db.findOne(HttpWagonConfig.class, null); if (c != null) { HttpWagonConfig hc = c.getDocument(HttpWagonConfig.class); return hc.getConnectTimeout(); } } return 10000; } static class HttpsSocketFactory implements SecureProtocolSocketFactory, HandshakeCompletedListener { private KeyManagerFactory kmf; private TrustManagerFactory tmf; public HttpsSocketFactory(KeyManagerFactory kmf, TrustManagerFactory tmf) { this.kmf = kmf; this.tmf = tmf; } @Override public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { return createSocket(host, port); } @Override public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort, HttpConnectionParams params) throws IOException, UnknownHostException, ConnectTimeoutException { return createSocket(host, port); } @Override public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException, UnknownHostException { return createSocket(host, port); } @Override public Socket createSocket(String host, int port) throws IOException, UnknownHostException { try { KeyManager[] keyManagers = null; if (kmf != null) keyManagers = kmf.getKeyManagers(); TrustManager[] trustManagers = null; if (tmf != null) trustManagers = tmf.getTrustManagers(); SSLContext ctx = SSLContext.getInstance("SSL"); ctx.init(keyManagers, trustManagers, new SecureRandom()); SSLSocket socket = (SSLSocket) ctx.getSocketFactory().createSocket(host, port); socket.setNeedClientAuth(true); socket.setEnabledCipherSuites(socket.getSupportedCipherSuites()); socket.addHandshakeCompletedListener(this); return socket; } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } return null; } @Override public void handshakeCompleted(HandshakeCompletedEvent event) { Logger logger = LoggerFactory.getLogger(HttpWagon.class); try { StringBuilder sb = new StringBuilder(4096); SSLSession session = event.getSession(); sb.append(String.format("cipher %s, protocol %s, peer %s, ", event.getCipherSuite(), session.getProtocol(), session.getPeerHost())); java.security.cert.Certificate[] certs = event.getPeerCertificates(); for (int i = 0; i < certs.length; i++) { if (!(certs[i] instanceof java.security.cert.X509Certificate)) continue; java.security.cert.X509Certificate cert = (java.security.cert.X509Certificate) certs[i]; System.out.println("Cert #" + i + ": " + cert.getSubjectDN().getName()); sb.append("\ncert #" + i + ": " + cert.getSubjectDN().getName()); } logger.debug("kraken core: handshake completed, {}", sb.toString()); } catch (Exception e) { logger.error("kraken core: handshake complete parse error", e); } } } }