hc-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From steve labar <steve.labarbera....@gmail.com>
Subject Re: SSL and HTTPService
Date Sat, 19 Nov 2011 20:34:29 GMT
Oleg,

I actually have few questions regarding your response after having thought
about this for a little while:

1. one thing that I might have failed to mention is this proxy needs to be
able to intercept and look at the request before it is being sent to the
origin server. The whole idea behind this proxy is to be a security tool to
be able to look and manipulate the request that has been sent by the
browser before it gets sent to the origin server. Now having said that in
this case wouldn't the proxy server need to establish an SSL handshake with
the browser so that the browser will trust and send that encrypted request
and your proxy will be able to decrypt the encrypted request?

2.if an NIO is going to be the best alternative I decided to use a class
called NHttpSSLServer which I found online that looks to be a good template
for trying to build this proxy that looks to be using Httpcomponents. The
question i I have is regarding how to explicitly implement the connect
request you mention as a part of number four in your response. Initially
upon creating the proxy I used the following snippet of code taken from
that class. The only difference is I use the non-ssl classes for my socket
and listeners:

   HttpRequestHandlerRegistry reqistry = new HttpRequestHandlerRegistry();
                reqistry.register("*", new DefaultHttpRequestHandler(this));

                handler.setHandlerResolver(reqistry);

                // Provide an event logger
                handler.setEventListener(new EventLogger());
                IOEventDispatch ioEventDispatch = new
DefaultServerIOEventDispatch(
                        handler,
                        params);


                ListeningIOReactor ioReactor = new
DefaultListeningIOReactor(2, params);

                try {
                    ioReactor.listen(new InetSocketAddress(8080));
                    ioReactor.execute(ioEventDispatch);
                } catch (InterruptedIOException ex) {
                    System.err.println("Interrupted");
                } catch (IOException e) {
                    System.err.println("I/O error: " + e.getMessage());
                }

at this point everything over http being sent to my proxy is working
perfectly. Now the hard part that I don't quite fully understand the
"Connect" request. Currently, I have a class called
DefaultHttpRequestHandler this is the class that currently looks at each of
the request that come in. initially when creating the proxy I pass a
reference of the proxy to that DefaultHttpRequestHandler.The idea behind
this is when I see the CONNECT inside my requesthandler i can take the
reference to the proxy and add another listener for the ssl traffic.
However how do i handle sorting what goes to the tunneled socket and what
does not? Still everything will always be coming in from the browser over
that initial socket over 8080 which was set when initially starting proxy.
So then even the newly encrypted traffic will be coming in from the 8080
socket then hitting that DefaultHttpRequestHandler. So do i track the
traffic inside the .handle() and route to that newly created ssl tunel
based on the host i see maybe and if i have created a tunnel w/ that host?
Because the browser on 8080 is not going to be able to ever send to a new
socket its always coming in from 8080. Can you see where i'm not clear?

So to reiterate.
1. Connect gets recognized within my
DefaultHttpRequestHandler.handle(HttpRequest request, HttpResponse response,
            HttpContext context) method so i do the following steps.

           a. create sslsocket with origin server pulled from CONNECT
request message.
           b. if connection can be established now go ahead send the
"HTTP/1.1 200 Connection established\r\nProxy-agent: proxy client\r\n\r\n"
to the browser.

2. Now this is where stuff gets fuzzy. At this point browser is closing the
connection I'm maybe assuming this is due to the fact that i may need to
establish a ssl trusted handshake before it will allow my proxy to receive
its encrypted data? Problem is the browser is sending its data to 8080 and
the serversockket setup is just a DefaultServerIOEventDispatch not a
SSLServerIOEventDispatch. This was what I thought my initial issues were.
but then it seemed like you were stating a normal proxy treats everything
it sees transparently. Which in that case whether encrypted or not is just
data you pass along to origin server. However, in my case i need to be able
to view that encrypted data then if necessary make changes then send to
origin. In essence I establish trusted handshakes from client (browser) to
my server and from my server to origin server.

Is this a big job? I think i'm way over my head here. Maybe I need to hire
out help! Is this a very complex task you think.?


On Fri, Nov 18, 2011 at 11:38 AM, steve labar <steve.labarbera.one@gmail.com
> wrote:

> Thank you for your response. You have got to get an award for how quickly
> and reliably you respond to peoples problems! You my friend deserve a medal!
>
> Thank again,
> Steve
>
>
> On Fri, Nov 18, 2011 at 7:32 AM, Oleg Kalnichevski <olegk@apache.org>wrote:
>
>> On Thu, Nov 17, 2011 at 08:48:16PM -0800, steve labar wrote:
>> > I'm trying to create a http/https proxy server leveraging httpclient and
>> > httpcore. I can get the http portion of the proxy to work just fine.
>> > However, when I try to implement the ssl section I have major trouble.
>> It
>> > looks like its failing within HTTPService.handleRequest(). I expect its
>> due
>> > to ssl but hard to really tell what i'm doing wrong. Here is what i'm
>> > currently doing:
>> >
>> > Setup socket to listen on 8080
>> >
>> > serversocket = new ServerSocket(port);
>> >             this.params = new SyncBasicHttpParams();
>> >
>> this.params.setBooleanParameter(ClientPNames.HANDLE_REDIRECTS,
>> > true).setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 50000)
>> >
>> > .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE,
>> >                             8 * 1024)
>> >                     .setBooleanParameter(
>> >                             CoreConnectionPNames.STALE_CONNECTION_CHECK,
>> > false)
>> >
>> .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY,
>> > true)
>> >                     .setParameter(CoreProtocolPNames.ORIGIN_SERVER,
>> >                             "HttpComponents/1.1");
>> >             // Set up the HTTP protocol processor
>> >             HttpProcessor httpproc = new ImmutableHttpProcessor(
>> >                     new HttpResponseInterceptor[] { new ResponseDate(),
>> >                             new ResponseServer(), new ResponseContent(),
>> >                             new ResponseConnControl() });
>> >
>> >             // Set up request handlers
>> >             HttpRequestHandlerRegistry reqistry = new
>> > HttpRequestHandlerRegistry();
>> >             reqistry.register("*", new DefaultHttpRequestHandler());
>> >             // Set up the HTTP service
>> >             this.httpService = new HttpService(httpproc,
>> >                     new DefaultConnectionReuseStrategy(),
>> >                     new DefaultHttpResponseFactory(), reqistry,
>> > this.params);
>> >
>> > Then on every incoming accept() on that socket i send that data to a
>> worker
>> > thread that calls httpservice.handlerequest() here is that code snippet:
>> >
>> > public void run() {
>> >             System.out.println("New connection thread");
>> >             HttpContext context = new BasicHttpContext(null);
>> >
>> >             try {
>> >                 while (!Thread.interrupted() && this.conn.isOpen())
{
>> >                     //HttpRequest req =
>> this.conn.receiveRequestHeader();
>> >                     this.httpservice.handleRequest(this.conn, context);
>> >                 }
>> >             } catch (ConnectionClosedException ex) {
>> >                 System.err.println("Client closed connection");
>> >             } catch (IOException ex) {
>> >                 System.err.println("I/O error: " + ex.getMessage());
>> >                 ex.printStackTrace();
>> >             } catch (HttpException ex) {
>> >                 System.err.println("Unrecoverable HTTP protocol
>> violation: "
>> >                         + ex.getMessage());
>> >             } finally {
>> >                 try {
>> >                     this.conn.shutdown();
>> >                 } catch (IOException ignore) {
>> >                 }
>> >             }
>> >
>> > Then each request gets handled by my DefaultHttpRequestHandler which
>> > extends HttpRequestHandler here is the method called anytime
>> > httpService.handleRequest() is called. You will notice I peek at the
>> > http(s) method if not a CONNECT. Its super simple make request to server
>> > and set the response object and let the method handle sending back to
>> > browser on socket listening. The problem comes up if i hit as an example
>> > https://google.com. When i debug it comes in gets set to handle() by
>> the
>> > httpservice.handlerequest(). As soon as it reaches the handle method I
>> peek
>> > and see its a Connect www.google.com:443. So, i make request with
>> > httpclient right here and get a 200 response so i know my proxy server
>> and
>> > the server(google) can accept ssl so at this point i set the response
>> to be
>> > HTTP/1.0 200 Connection established\r\nProxy-agent: proxy
>> client\r\n\r\n"
>> > just as RFC says you do to tell browser we can start talking in ssl.
>> But as
>> > soon as i set this as response and it leaves the method it shuts
>> connection
>> > down and Firefox says:
>> >
>> >  Secure Connection Failed
>> >
>> > An error occurred during a connection to www.google.com.
>> >
>> > SSL received a record that exceeded the maximum permissible length.
>> >
>> > (Error code: ssl_error_rx_record_too_long)
>> >
>> > I have read online and it says that this happens if you try to send ssl
>> to
>> > port 80 but i'm pretty sure that is not problem. Any ideas?
>> >
>>
>> Hi Steve
>>
>> SSL tunneling via an HTTP proxy simply does not work like that. Upon
>> receipt of a CONNECT request, the proxy is expected to do the following:
>> (1) optionally authenticate the user and respond with 407 status if user
>> credentials are not valid
>> (2) open a TCP connection to the origin server, but send NO data to the
>> origin
>> (3) if connection is successful, respond to the client with 200 status
>> (4) at this point the tunnel can be considered established and
>> operational. From hence on the proxy is expected to read whatever data
>> comes from the client and relay it to the origin and the other way around.
>> The content passed between the client and the origin is completely opaque
>> to the proxy.
>>
>> For proper specification of the protocol please see
>>
>> http://www.ietf.org/rfc/rfc2817.txt
>>
>> The trouble is that connection tunneling is not easy to implement with
>> the classic (blocking) I/O. One would need to employ two treads to be able
>> to read and write in both directions simultaneously or use one thread and
>> constantly switch between read and write mode which may be not very
>> efficient. Usually NIO tends to be a better model for proxies.
>>
>> Oleg
>>
>>
>>
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe@hc.apache.org
>> For additional commands, e-mail: dev-help@hc.apache.org
>>
>>
>

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message