users@jersey.java.net

[Jersey] Re: Problem with concurrent HTTP client and proxy authentication in Jersey 2.5

From: Miroslav Fuksa <miroslav.fuksa_at_oracle.com>
Date: Tue, 7 Jan 2014 13:06:39 +0100

Hi Ian,

thank you for your email. I have investigated the issue and there is a bug in Jersey. It looks like the second request (step 6 in your first scenario) does not use ApacheConnector again. It uses HttpUrlConnector (default settings) and proxy settings are ignored by this connector.

I have created a bug record:

https://java.net/jira/browse/JERSEY-2318

The workaround could be to use the default provider (HttpUrlConnectorProvider) and to configure the proxy information using the system properties. If you don’t want to use system properties, you can use HttpUrlConnectorProvider.ConnectionFactory and return connection that are configured for proxy. I have not tested it but I think this could work. See for example:
http://stackoverflow.com/questions/1432961/how-do-i-make-httpurlconnection-use-a-proxy

Thanks
Mira

  

On Dec 20, 2013, at 3:42 PM, Ian Thomas <ian.thomas_at_linguamatics.com> wrote:

> Hi,
>
> I maintain a Jersey-based library for communicating with a RESTful web service that requires Basic HTTP authentication. This library must support communicating through an HTTP proxy server which itself requires either Basic, Digest or NTLM authentication. The library was previously working well with Jersey v2.0 except in the case of POST-ing or PUT-ing data to the web service via an authenticating proxy server, when I would get the following Exception:
>
> org.apache.http.client.NonRepeatableRequestException: Cannot retry request with a non-repeatable request entity.
>
> The background to this issue is captured in a currently unanswered StackOverflow question:
>
> http://stackoverflow.com/questions/19681965/reuse-authorization-header-to-prevent-multiple-407-proxy-authentication-challeng
>
> I was hoping the resolutions to the following Jersey issues in v2.5 would help me in this regard as I could buffer my outgoing requests and make them "repeatable" in case of any authentication challenges:
>
> https://java.net/jira/browse/JERSEY-2128
>
> https://java.net/jira/browse/JERSEY-2224
>
> I have therefore just upgraded my project to use Jersey v2.5 with Jersey Apache Connector v2.5 and Apache HttpClient v4.3.1. I am now seeing some problems when connecting to the RESTful service via a proxy server that requires Basic authentication. I am wondering whether I am simply not using the new Jersey v2.5 API correctly, or if there is an underlying issue here.
>
> The fundamental problem seems to be that Jersey will not include *both* the required 'Proxy-Authorization' and 'Authorization' HTTP headers at the same time.
>
> Here is the series of events I am currently observing with a basic HEAD request using Jersey v2.5:
>
> ====
> 1) Request to RESTful service via proxy server.
> 2) 407 challenge from proxy server.
> 3) Repeat original request with additional 'Proxy-Authorization' header.
> 4) 401 challenge from RESTful service (via proxy).
> 5) Repeat original request with 'Authorization' header (but without previously included 'Proxy-Authorization' header).
> 6) 407 challenge from proxy server.
> 7) Jersey request finishes with final outcome of 407.
> ====
>
> Here is the series of events that I expect to happen using Jersey v2.5 in non-preemptive authentication mode, based on my previous experiences with Jersey v2.0:
>
> ====
> 1) Request to RESTful service via proxy server.
> 2) 407 challenge from proxy server.
> 3) Repeat original request with additional 'Proxy-Authorization' header.
> 4) 401 challenge from RESTful service (via proxy).
> 5) Repeat original request with additional 'Authorization' header (as well as 'Proxy-Authorization' header).
> 6) Success - correct response from RESTful service (via proxy).
> ====
>
> Here is a simplified representation of the old code I used in Jersey v2.0:
>
> ====
> final ClientConfig config = new ClientConfig();
>
> config.property(ApacheClientProperties.PROXY_URI, "http://www.proxy.com:9999");
> config.property(ApacheClientProperties.PROXY_USERNAME, "proxyuser");
> config.property(ApacheClientProperties.PROXY_PASSWORD, "proxypassword");
>
> final ApacheConnector connector = new ApacheConnector(config);
> config.connector(connector);
>
> final Client client = ClientBuilder.newClient(config);
>
> client.register( new HttpBasicAuthFilter("user", "password") );
> ====
>
> And here is a simplified representation of the new Jersey v2.5 code:
>
> ====
> final ClientConfig config = new ClientConfig();
>
> config.property(ClientProperties.PROXY_URI, "http://www.proxy.com:9999");
> config.property(ClientProperties.PROXY_USERNAME, "proxyuser");
> config.property(ClientProperties.PROXY_PASSWORD, "proxypassword");
>
> config.connectorProvider( new ApacheConnectorProvider() );
>
> final Client client = ClientBuilder.newClient(config);
>
> final HttpAuthenticationFeature authFeature = HttpAuthenticationFeature
> .basicBuilder()
> .nonPreemptive()
> .credentials("user", "password")
> .build();
> client.register(authFeature);
> ====
>
> I have experimented with different values for the following configuration properties, but I cannot find a combination that fixes the problem:
>
> ====
>
> ApacheClientProperties.PREEMPTIVE_BASIC_AUTHENTICATION
>
> ClientProperties.REQUEST_ENTITY_PROCESSING
>
> ====
>
> I have also tried using a pre-emptive basic 'HttpAuthenticationFeature' instead, but again this does not actually resolve my problem.
>
> Please can somebody let me know if I need to change anything or add anything to make this work properly in Jersey v2.5?
>
> Thanks very much,
>
> Ian
>