Pregunta

I am using the Jersey Client 2.0 library (with Apache HttpClient v4.2.5 transport connector) to consume a RESTful web service. My application must support connections via a proxy server with any of Basic, Digest or NTLM authentication. I have added support for all these types of proxy authentication and essentially everything is working correctly.

This is how I added support for Basic and Digest proxy authentication:

ClientConfig config = new ClientConfig();
config.property(ApacheClientProperties.PROXY_URI, "http://www.proxy.com:5678");
config.property(ApacheClientProperties.PROXY_USERNAME, "proxy_user");
config.property(ApacheClientProperties.PROXY_PASSWORD, "proxy_password");
ApacheConnector connector = new ApacheConnector(config);
config.connector(connector);
Client client = ClientBuilder.newClient(config);

In addition, the RESTful web service I am connecting to also requires Basic authentication itself, which I handle using the following:

client.register( new HttpBasicAuthFilter("user", "password") );

However, my application is not behaving exactly as I want: it seems that every individual HTTP request that I make is resulting in a 407 authentication challenge response from the proxy server. This is an issue for two reasons:

  1. If I make a POST or PUT request (having already successfully authenticated with the proxy server in the previous request) with the entity body supplied by an InputStream, it is deemed to be a "non-repeatable" request so when the 407 challenge is received I get the following exception:

    org.apache.http.client.NonRepeatableRequestException: Cannot retry request with a non-repeatable request entity.
    

    I could work around this issue by buffering the entity body data from the InputStream into a string or byte array so that the request is repeatable in case a 407 challenge is received, but this is inefficient and doesn't address issue 2.

  2. Having to duplicate every request, first to trigger the 407 challenge and then to repeat with the necessary additional HTTP headers in place for proxy authentication, is very inefficient. Some of my client operations involve numerous HTTP requests to the RESTful web service, so this additional traffic and latency is unfortunate.

My expectation is that once the Jersey client has successfully authenticated with the proxy server the first time, all subsequent requests made using the same Client instance would automatically include the necessary Proxy-Authorization header to prevent any further 407 challenges. This seems to be the standard approach for HTTP 1.1 as per this link:

A proxy server sends the client a Proxy-Authenticate header, containing a challenge, in a 407 (Proxy Authentication Required) response. The client then repeats the initial request, but adds a Proxy-Authorization header that contains credentials appropriate to the challenge. After successful proxy authentication, a client typically sends the same Proxy-Authorization header to the proxy with each subsequent request, rather than wait to be challenged again.

So my question is what configuration settings do I need to apply to either the Jersey Client or the underlying Apache HttpClient transport layer to enable this behaviour? I have seen various other posts recommending the manual addition of the Proxy-Authorization header, but I would rather avoid this workaround if possible. I am also ideally looking for a solution that will work with all three types of proxy authentication I'm using (Basic, Digest and NTLM).

If it is not possible to prevent all these extra 407 challenges, I would also like recommendations for the best approach when POSTing or PUTing data from local files in a "repeatable" way to prevent issues following a 407 proxy authentication challenge.

¿Fue útil?

Solución

In the end, I resolved issue 1 by upgrading my project to Jersey Client v2.6 and configuring the client to automatically buffer all my POST/PUT requests such that they are "repeatable" in response to any 407 challenges that come back from the proxy server.

Request buffering can be enabled in Jersey Client v2.5+ by setting the following property on the ClientConfig object, which changes the request entity processing mode from "chunked" (the default) to "buffered":

config.property(ClientProperties.REQUEST_ENTITY_PROCESSING,
                RequestEntityProcessing.BUFFERED);

This is now working for me with all three types of proxy authentication that I have to support: Basic, Digest and NTLM. I only enable this "buffered" mode when the user has configured a proxy server, as I think it's best to stick with the default "chunked" mode unless absolutely necessary. I worry about the overhead of buffering large PUT/POST requests in memory, and the potential loss of efficiency in not chunking the data.

So now my client application works properly, but I would still be very interested to hear about any possible solutions to issue 2, as it would be preferable to only trigger a single initial 407 proxy authentication challenge per Client instance. I suspect any potential solution for this issue would only work for Basic authentication anyway, due to the inherent additional complexities of Digest and NTLM authentication.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top