/* * 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 * */ package org.owasp.proxy.ajp; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.cert.X509Certificate; import java.util.Enumeration; import org.junit.Ignore; import org.junit.Test; import org.owasp.proxy.daemon.Server; import org.owasp.proxy.http.MessageFormatException; import org.owasp.proxy.http.MessageUtils; import org.owasp.proxy.http.MutableBufferedResponse; import org.owasp.proxy.http.StreamingRequest; import org.owasp.proxy.http.StreamingResponse; import org.owasp.proxy.util.AsciiString; public class AJPClientTest { private static X509Certificate loadCertificate(InputStream in, char[] password) throws GeneralSecurityException, IOException { KeyStore ks = KeyStore.getInstance("PKCS12"); ks.load(in, password); Enumeration<String> aliases = ks.aliases(); String alias = null; if (aliases.hasMoreElements()) alias = aliases.nextElement(); return (X509Certificate) ks.getCertificate(alias); } private AJPRequestHandler handler = new AJPRequestHandler() { public void dispose() throws IOException { } public StreamingResponse handleRequest(InetAddress source, AJPRequest request) throws IOException, MessageFormatException { StreamingResponse resp = new StreamingResponse.Impl(); // System.out.println(request.toString()); String cl = request.getHeader("Content-Length"); if (cl != null) { int len = Integer.parseInt(cl); validatePayload(len, request.getContent()); resp.setHeader(AsciiString .getBytes("HTTP/1.1 200 Ok\r\nContent-Length: " + cl + "\r\n\r\n")); resp.setContent(generatePayload(len)); } else { resp .setHeader(AsciiString .getBytes("HTTP/1.0 200 Ok\r\nContent-Length: 16\r\n\r\n")); resp.setContent(new ByteArrayInputStream(AsciiString .getBytes("0123456789ABCDEF"))); } return resp; } }; @Test @Ignore("Requires an AJP server on the other end") public void testCertificate() throws Exception { InetSocketAddress ajp = new InetSocketAddress("localhost", 8009); AJPClient connection = new AJPClient(); connection.connect(ajp); AJPProperties properties = connection.getProperties(); properties.getRequestAttributes().put("w00t", "WAIT"); InputStream in = AJPClientTest.class.getClassLoader() .getResourceAsStream("org/owasp/proxy/daemon/server.p12"); if (in == null) { System.err.println("Can't find keystore"); return; } X509Certificate cert = loadCertificate(in, "password".toCharArray()); properties.setSslCert(cert); properties.setSslCipher("TLS_DHE_DSS_WITH_AES_128_CBC_SHA"); properties.setSslKeySize("2048"); properties.setSslSession("SSLSession"); StreamingRequest request = new StreamingRequest.Impl(); StreamingResponse response; MutableBufferedResponse b; InetSocketAddress target = new InetSocketAddress("localhost", 80); request.setTarget(target); request.setSsl(true); request.setMethod("GET"); request.setResource("/cachetest/Snoop"); request.setVersion("HTTP/1.0"); request.setHeader("User-Agent", "AJPClient"); response = connection.fetchResponse(request); b = new MutableBufferedResponse.Impl(); MessageUtils.buffer(response, b, Integer.MAX_VALUE); System.out.println(b); connection.close(); } @Test @Ignore("Requires an AJP server on the other end") public void ping() throws Exception { InetSocketAddress ajp = new InetSocketAddress("localhost", 8009); AJPClient connection = new AJPClient(); connection.connect(ajp); for (int i = 0; i < 15; i++) if (!connection.ping()) System.out.println("Ping failed!"); connection.close(); } private void doPost(AJPClient connection, int size) throws Exception { System.out.println("POSTing " + size); StreamingRequest request = new StreamingRequest.Impl(); request.setTarget(new InetSocketAddress("localhost", 80)); request.setMethod("POST"); request.setResource("/cachetest/Snoop"); request.setVersion("HTTP/1.0"); request.setHeader("Content-Type", "application/x-www-form-urlencoded"); request.setHeader("Content-Length", Integer.toString(size)); request.setHeader("User-Agent", "AJPClient"); request.setContent(generatePayload(size)); StreamingResponse response = connection.fetchResponse(request); System.out.println(response); validatePayload(size, response.getContent()); System.out.println("POST completed"); } @Test @Ignore("Requires an AJP server on the other end") public void testTomcat() throws Exception { InetSocketAddress ajp = new InetSocketAddress("localhost", 8009); AJPClient client = new AJPClient(); client.connect(ajp); client.setTimeout(1000); doPosts(client); } @Test public void testConnectionHandler() throws Exception { InetSocketAddress ajp = new InetSocketAddress("localhost", 8010); Server server = new Server(ajp, new AJPConnectionHandler(handler)); server.start(); AJPClient client = new AJPClient(); client.setTimeout(1000); client.connect(ajp); doPosts(client); server.stop(); } private void doPosts(AJPClient client) throws Exception { doPost(client, 16); doPost(client, 1024); doPost(client, 1025); doPost(client, AJPConstants.MAX_READ_SIZE); doPost(client, 8192); doPost(client, 8197); doPost(client, 16384); doPost(client, 16602); doPost(client, 32921); doPost(client, 1234567); client.close(); } private static InputStream generatePayload(int size) { byte[] buff = new byte[size]; for (int i = 0; i < size; i++) buff[i] = (byte) (i % 0xFF); return new ByteArrayInputStream(buff); } private static void validatePayload(int size, InputStream in) throws IOException { if (in != null) { byte[] buff = new byte[1024]; int got, read = 0; while ((got = in.read(buff)) > -1) { for (int i = 0; i < got; i++) { if (read + i < size && buff[i] != (byte) ((read + i) % 0xFF)) { throw new RuntimeException("Error at " + (read + i) + ": Expected " + ((byte) ((read + i) % 0xFF)) + ", got " + buff[i]); } } read += got; } if (read != size) throw new RuntimeException("Expected " + size + ", got " + read); } else { if (size > 0) { throw new RuntimeException("Expected " + size + ", got nothing at all"); } } } }