package com.intuit.tank.proxy;
/*
* #%L
* proxy-extension
* %%
* Copyright (C) 2011 - 2015 Intuit Inc.
* %%
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
* #L%
*/
/*
* This file is part of the OWASP Proxy, a free intercepting proxy library.
* Copyright (C) 2008-2010 Rogan Dawes <rogan@dawes.za.net>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to:
* The Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
import java.io.File;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.security.GeneralSecurityException;
import java.security.cert.CertificateEncodingException;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Logger;
import javax.security.auth.x500.X500Principal;
import org.owasp.proxy.daemon.LoopAvoidingTargetedConnectionHandler;
import org.owasp.proxy.daemon.Proxy;
import org.owasp.proxy.daemon.ServerGroup;
import org.owasp.proxy.daemon.TargetedConnectionHandler;
import org.owasp.proxy.http.server.BufferedMessageInterceptor;
import org.owasp.proxy.http.server.DefaultHttpRequestHandler;
import org.owasp.proxy.http.server.HttpProxyConnectionHandler;
import org.owasp.proxy.http.server.HttpRequestHandler;
import org.owasp.proxy.http.server.LoggingHttpRequestHandler;
import org.owasp.proxy.socks.SocksConnectionHandler;
import org.owasp.proxy.ssl.AutoGeneratingContextSelector;
import org.owasp.proxy.ssl.SSLConnectionHandler;
import org.owasp.proxy.ssl.SSLContextSelector;
import org.owasp.proxy.util.TextFormatter;
import com.intuit.tank.conversation.Transaction;
import com.intuit.tank.entity.Application;
import com.intuit.tank.handler.BufferingHttpRequestHandler;
import com.intuit.tank.handler.ProxyDefaultHttpRequestHandler;
import com.intuit.tank.interceptor.ProxyBufferedMessageInterceptor;
import com.intuit.tank.proxy.config.ProxyConfiguration;
import com.intuit.tank.proxy.table.TransactionRecordedListener;
import com.intuit.tank.selector.TankProxySelector;
public class EmbeddedProxy implements TransactionRecordedListener {
private static Logger logger = Logger.getLogger("org.owasp.proxy");
private static char[] CA_PASSWORD = "password".toCharArray();
private static String CA_TYPE = "PKCS12";
private static String CA_ALIAS = "CA";
private ProxyConfiguration config;
private Proxy p;
private Application application;
static {
System.setProperty("https.protocols", "TLSv1.1");
}
/**
*
*/
public EmbeddedProxy(ProxyConfiguration config) {
this.application = new Application(config);
this.config = config;
}
public void start() {
try {
application.startSession(this);
logger.setUseParentHandlers(false);
Handler ch = new ConsoleHandler();
ch.setFormatter(new TextFormatter());
logger.addHandler(ch);
InetSocketAddress listen;
try {
listen = new InetSocketAddress("localhost", config.getPort());
} catch (NumberFormatException nfe) {
return;
}
DefaultHttpRequestHandler drh = new ProxyDefaultHttpRequestHandler(
getProxySelector());
ServerGroup sg = new ServerGroup();
sg.addServer(listen);
drh.setServerGroup(sg);
BufferedMessageInterceptor bmi = new ProxyBufferedMessageInterceptor();
HttpRequestHandler rh = new BufferingHttpRequestHandler(
new LoggingHttpRequestHandler(drh), bmi, 1024 * 1024,
application);
HttpProxyConnectionHandler hpch = new HttpProxyConnectionHandler(rh);
TargetedConnectionHandler tch = new LoopAvoidingTargetedConnectionHandler(
sg, new SSLConnectionHandler(getSSLContextSelector(), true,
hpch));
hpch.setConnectHandler(tch);
TargetedConnectionHandler socks = new SocksConnectionHandler(tch,
true);
p = new Proxy(listen, socks, null);
p.setSocketTimeout(90000);
p.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public void stop() {
if (p != null) {
try {
p.stop();
application.endSession();
System.out.println("Terminated");
p = null;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/**
* Returns a proxy selector
*
* @param proxy
* @return
*/
private ProxySelector getProxySelector() {
ProxySelector ps = new TankProxySelector(java.net.Proxy.NO_PROXY);
return ps;
}
/**
* Uses an AutoGeneratingContextSelector to generate a certificate authority
* but does not return it only because we're going to load it with the
* 'useExistingKeystore' method instead.
*
* @param ks
* File representing the certificate authority file we're
* generating.
*/
public static void generateKeystore(File ks)
throws GeneralSecurityException, CertificateEncodingException,
IOException {
X500Principal ca = new X500Principal(
"cn=OWASP Custom CA for Tank,ou=Tank Custom CA,o=Tank,l=Tank,st=Tank,c=Tank");
AutoGeneratingContextSelector ssl = null;
try {
ssl = new AutoGeneratingContextSelector(ca);
ssl.save(ks, CA_TYPE, CA_PASSWORD, CA_PASSWORD, CA_ALIAS);
} catch (GeneralSecurityException e) {
System.err.println("Error saving CA keys to keystore: "
+ e.getLocalizedMessage());
throw e;
} catch (IOException e) {
System.err.println("Error saving CA keys to keystore: "
+ e.getLocalizedMessage());
throw e;
}
}
/**
* Attempts to load an existing certificate authority file, throws Exception
* on failure.
*
* @param ks
* @return
*/
private AutoGeneratingContextSelector useExistingKeystore(File ks)
throws GeneralSecurityException, IOException {
try {
return new AutoGeneratingContextSelector(ks, CA_TYPE, CA_PASSWORD,
CA_PASSWORD, CA_ALIAS);
} catch (GeneralSecurityException e) {
System.err.println("Error loading CA keys from keystore: "
+ e.getLocalizedMessage());
throw e;
} catch (IOException e) {
System.err.println("Error loading CA keys from keystore: "
+ e.getLocalizedMessage());
throw e;
}
}
private SSLContextSelector getSSLContextSelector()
throws GeneralSecurityException, IOException {
File ks = new File(config.getCertificateAuthorityPath());
if (!ks.exists()) {
generateKeystore(ks);
}
return useExistingKeystore(ks);
}
/**
* @{inheritDoc
*/
public void transactionProcessed(Transaction t, boolean filtered) {
// don't know if we need to do something here
}
}