Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [jetty-users] HttpClient proxy tunnel pre-authentication

That worked well - thank you!

However I'm hitting a second problem, this time with Digest auth to the proxy. This appears to be a bug in HttpProxyClientConnectionFactory.ProxyPromise.tunnel.

When tunnel is called, in my case, the target is being set to "hawker.flyer.qagood.com:443".

org.eclipse.jetty.client.HttpProxy.HttpProxyClientConnectionFactory.ProxyPromise.tunnel(HttpDestination, Connection)
            private void tunnel(HttpDestination destination, final Connection connection)
            {
                String target = destination.getOrigin().getAddress().asString();
                Origin.Address proxyAddress = destination.getConnectAddress();
                HttpClient httpClient = destination.getHttpClient();
                Request connect = httpClient.newRequest(proxyAddress.getHost(), proxyAddress.getPort())
                        .scheme(HttpScheme.HTTP.asString())
                        .method(HttpMethod.CONNECT)
                        .path(target)
                        .header(HttpHeader.HOST, target)
                        .timeout(httpClient.getConnectTimeout(), TimeUnit.MILLISECONDS);

So when path(target) is invoked we wind up calling URI.create("hawker.flyer.qagood.com:443")

    public Request path(String path)
    {
        URI uri = URI.create(path);
        String rawPath = uri.getRawPath();
        if (uri.isOpaque())
            rawPath = path;
        if (rawPath == null)
            rawPath = "";
        this.path = rawPath;

This produces a uri with scheme = "hawker.flyer.qagood.com" which is wrong and this.path ends up null (via uri.getRawPath()).

Later on, that causes a NullPointerException when buildUri tries to use the path:

    private URI buildURI(boolean withQuery)
    {
        String path = getPath();
        String query = getQuery();
        if (query != null && withQuery)
            path += "?" + query;
        URI result = URI.create(path);

The stacktrace for the exception is:

Thread [HttpClient@774730085-17] (Suspended (exception NullPointerException))	
	URI$Parser.parse(boolean) line: not available	
	URI.<init>(String) line: not available	
	URI.create(String) line: not available	
	HttpRequest.buildURI(boolean) line: 691	
	HttpRequest.getURI() line: 191	
	DigestAuthentication$DigestResult.apply(Request) line: 223	
	AuthenticationProtocolHandler$AuthenticationListener.onComplete(Result) line: 145	
	ResponseNotifier.notifyComplete(Response$CompleteListener, Result) line: 215	
	ResponseNotifier.notifyComplete(List<ResponseListener>, Result) line: 207	
	HttpReceiverOverHTTP(HttpReceiver).responseSuccess(HttpExchange) line: 350	
	HttpReceiverOverHTTP.messageComplete() line: 196	
	HttpParser.parseNext(ByteBuffer) line: 1224	
	HttpReceiverOverHTTP.parse(ByteBuffer) line: 116	
	HttpReceiverOverHTTP.receive() line: 82	
	HttpChannelOverHTTP.receive() line: 75	
	HttpConnectionOverHTTP.onFillable() line: 103	
	AbstractConnection$1.run() line: 505	
	QueuedThreadPool.runJob(Runnable) line: 607	
	QueuedThreadPool$3.run() line: 536	
	Thread.run() line: not available	

-----Original Message-----
From: jetty-users-bounces@xxxxxxxxxxx [mailto:jetty-users-bounces@xxxxxxxxxxx] On Behalf Of Simone Bordet
Sent: Tuesday, February 11, 2014 2:32 AM
To: JETTY user mailing list
Subject: Re: [jetty-users] HttpClient proxy tunnel pre-authentication

Hi,

On Tue, Feb 11, 2014 at 3:07 AM, Gautam Pulla <gpulla@xxxxxxxx> wrote:
> Hello,
>
>
>
> I’m trying to use the HttpClient from Jetty 9.1.1.v20140108 to tunnel 
> through a proxy-server using proxy-authentication.
>
>
>
> I see that the Jetty client connects to the proxy without credentials, 
> upon which the proxy sends a 407 “proxy authentication required” response back.
> The Jetty client then looks in the HTTP authentication store for 
> suitable credentials (with matching realm & URI) to use in the next 
> request on the connection.
>
>
>
> The problem is, some proxies, such as Squid promptly drop the 
> connection upon authentication failure – and there is no opportunity 
> to submit a second request with the proxy-authenticate header.
>
>
>
> Following are the request & response logged by Jetty which shows that 
> no authentication header was initially sent. The “Connection: close” 
> header from Squid shows that the connection is dropped by Squid on an 
> auth failures.
>
>
>
> 17:56:11.159
> [HttpClient@469537924-12-selector-ClientSelectorManager@18688fe1/0] 
> DEBUG org.eclipse.jetty.client.HttpSender - Request headers 
> HttpRequest[CONNECT
> hawker.flyer.qagood.com:443 HTTP/1.1]@7a7ac5
>
> Accept-Encoding: gzip
>
> Host: hawker.flyer.qagood.com:443
>
> User-Agent: Jetty/9.1.1.v20140108
>
>
>
> 17:56:11.182 [HttpClient@469537924-18] DEBUG 
> o.eclipse.jetty.client.HttpReceiver - Response headers 
> HttpResponse[HTTP/1.0
> 407 Proxy Authentication Required]@4838eb55
>
> Server: squid/2.7.STABLE8
>
> Date: Tue, 11 Feb 2014 01:56:11 GMT
>
> Content-Type: text/html
>
> Content-Length: 1373
>
> X-Squid-Error: ERR_CACHE_ACCESS_DENIED 0
>
> Proxy-Authenticate: Basic realm="Squid proxy-caching web server"
>
> X-Cache: MISS from GASLAMP03.ocs.qagood.com
>
> X-Cache-Lookup: NONE from GASLAMP03.ocs.qagood.com:3128
>
> Via: 1.0 GASLAMP03.ocs.qagood.com:3128 (squid/2.7.STABLE8)
>
> Connection: close
>
>
>
> This is the Jetty HttpClient related code that creates the CONNECT 
> request & sends it to the proxy, and clearly there is no 
> authentication header supplied at this stage:
>
>
>
> org.eclipse.jetty.client.HttpProxy.HttpProxyClientConnectionFactory.Pr
> oxyPromise.tunnel(HttpDestination,
> Connection)
>
>
>
>             private void tunnel(HttpDestination destination, final 
> Connection connection)
>
>             {
>
>                 String target =
> destination.getOrigin().getAddress().asString();
>
>                 Origin.Address proxyAddress = 
> destination.getConnectAddress();
>
>                 HttpClient httpClient = destination.getHttpClient();
>
>                 Request connect =
> httpClient.newRequest(proxyAddress.getHost(), proxyAddress.getPort())
>
>                         .scheme(HttpScheme.HTTP.asString())
>
>                         .method(HttpMethod.CONNECT)
>
>                         .path(target)
>
>                         .header(HttpHeader.HOST, target)
>
>                         .timeout(httpClient.getConnectTimeout(),
> TimeUnit.MILLISECONDS);

Confirmed, it's a bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=427878

> Is there a way to make this scenario work? What seems to be required 
> is the ability to ‘pre-authenticate’.

Yes, that exposes bug2 :( but you can work it around in this way:

final URI uri = URI.create("http://localhost:"; + proxyPort()); final String value = "Basic " + B64Code.encode("user:password", StandardCharsets.ISO_8859_1); httpClient.getAuthenticationStore().addAuthenticationResult(new
Authentication.Result()
{
    @Override
    public URI getURI()
    {
        return uri;
    }

    @Override
    public void apply(org.eclipse.jetty.client.api.Request request)
    {
        request.header(HttpHeader.PROXY_AUTHORIZATION, value);
    }
});

Bug2 is that class BasicAuthentication.BasicResult should be public in order to allow you a simpler way to add authentication results.

--
Simone Bordet
----
http://cometd.org
http://webtide.com
http://intalio.com
Developer advice, training, services and support from the Jetty & CometD experts.
Intalio, the modern way to build business applications.
_______________________________________________
jetty-users mailing list
jetty-users@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/jetty-users

Back to the top