You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@hc.apache.org by "Oleg Kalnichevski (JIRA)" <ji...@apache.org> on 2017/02/05 12:27:42 UTC

[jira] [Resolved] (HTTPASYNC-110) Proxy reuses a fully established routed authenticated connection in attempt to CONNECT to target again causing 400 and NPE

     [ https://issues.apache.org/jira/browse/HTTPASYNC-110?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Oleg Kalnichevski resolved HTTPASYNC-110.
-----------------------------------------
       Resolution: Fixed
    Fix Version/s: 4.1.3

Fixed in SVN 4.1.x branch. Please re-test and close.

Oleg

> Proxy reuses a fully established routed authenticated connection in attempt to CONNECT to target again causing 400 and NPE
> --------------------------------------------------------------------------------------------------------------------------
>
>                 Key: HTTPASYNC-110
>                 URL: https://issues.apache.org/jira/browse/HTTPASYNC-110
>             Project: HttpComponents HttpAsyncClient
>          Issue Type: Bug
>            Reporter: Andrey K
>             Fix For: 4.1.3
>
>         Attachments: buglog.txt
>
>
> First I noticed I was getting sporadic errors when attempting to make an HTTPS call via HTTP Proxy that requires authentication:
> java.lang.IllegalArgumentException: Auth scheme may not be null
> 	at org.apache.http.util.Args.notNull(Args.java:54)
> 	at org.apache.http.impl.client.AuthenticationStrategyImpl.authSucceeded(AuthenticationStrategyImpl.java:215)
> 	at org.apache.http.impl.client.ProxyAuthenticationStrategy.authSucceeded(ProxyAuthenticationStrategy.java:43)
> 	at org.apache.http.impl.auth.HttpAuthenticator.isAuthenticationRequested(HttpAuthenticator.java:88)
> 	at org.apache.http.impl.nio.client.MainClientExec.needAuthentication(MainClientExec.java:629)
> 	at org.apache.http.impl.nio.client.MainClientExec.handleResponse(MainClientExec.java:569)
> 	at org.apache.http.impl.nio.client.MainClientExec.responseReceived(MainClientExec.java:309)
> 	at org.apache.http.impl.nio.client.DefaultClientExchangeHandlerImpl.responseReceived(DefaultClientExchangeHandlerImpl.java:147)
> 	at org.apache.http.nio.protocol.HttpAsyncRequestExecutor.responseReceived(HttpAsyncRequestExecutor.java:303)
> 	at org.apache.http.impl.nio.DefaultNHttpClientConnection.consumeInput(DefaultNHttpClientConnection.java:255)
> 	at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:81)
> 	at org.apache.http.impl.nio.client.InternalIODispatch.onInputReady(InternalIODispatch.java:39)
> 	at org.apache.http.impl.nio.reactor.AbstractIODispatch.inputReady(AbstractIODispatch.java:121)
> 	at org.apache.http.impl.nio.reactor.BaseIOReactor.readable(BaseIOReactor.java:162)
> 	at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvent(AbstractIOReactor.java:337)
> 	at org.apache.http.impl.nio.reactor.AbstractIOReactor.processEvents(AbstractIOReactor.java:315)
> 	at org.apache.http.impl.nio.reactor.AbstractIOReactor.execute(AbstractIOReactor.java:276)
> 	at org.apache.http.impl.nio.reactor.BaseIOReactor.execute(BaseIOReactor.java:104)
> 	at org.apache.http.impl.nio.reactor.AbstractMultiworkerIOReactor$Worker.run(AbstractMultiworkerIOReactor.java:588)
> Upon closer look with trace debug, I saw that it was breaking on an unexpected 400 status code coming back against a CONNECT+AUTH request. When I traced the connection that was used for this connect, I saw that it was a fully connected routed connection. What happened was the HttpClient got a 407 after attempting to do a CONNECT and that 407 contained instruction to close connection. HttpClient discarded the connection and obtained a new one from the pool but the one that was leased was already fully authenticated and tunneled. Thus the CONNECT request was sent to the actual tunneled target and returned with a 400.
> As a workaround I have enhanced a custom ProxyAuthenticationStrategy to rename the USER_TOKEN context value to a temporary unique value to prevent reusing a fully established connection and then revert it back after authentication is sucessful:
>   static AtomicLong counter = new AtomicLong(0);
>   static final String ORIGINAL_USER_TOKEN = "ORIGINAL_USER_TOKEN";
>   @Override
>   public Map<String, Header> getChallenges(HttpHost authhost, HttpResponse response, HttpContext context) throws MalformedChallengeException {
>     String originalUserToken = (String)context.getAttribute(ORIGINAL_USER_TOKEN);
>     if (originalUserToken == null) {
>       originalUserToken = (String)context.getAttribute(HttpClientContext.USER_TOKEN);
>       context.setAttribute(ORIGINAL_USER_TOKEN, originalUserToken);
>       String temporaryName = "NON-REUSABLE-" + counter.incrementAndGet();
>       context.setAttribute(HttpClientContext.USER_TOKEN, temporaryName);
>       log.trace("OnAuth: Renaming connection from {} to {}", originalUserToken, temporaryName);
>     }
>     return super.getChallenges(authhost, response, context);
>   }
>   @Override
>   public void authSucceeded(HttpHost authhost, AuthScheme authScheme, HttpContext context) {
>     String originalUserToken = (String)context.getAttribute(ORIGINAL_USER_TOKEN);
>     if (originalUserToken != null) {
>       String tempUserToken = (String)context.getAttribute(HttpClientContext.USER_TOKEN);
>       context.setAttribute(HttpClientContext.USER_TOKEN, originalUserToken);
>       context.removeAttribute(ORIGINAL_USER_TOKEN);
>       log.trace("OnAuthSucc: Renaming connection from {} to {}", tempUserToken, originalUserToken);
>     }
>     super.authSucceeded(authhost, authScheme, context);
>   }



--
This message was sent by Atlassian JIRA
(v6.3.15#6346)

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@hc.apache.org
For additional commands, e-mail: dev-help@hc.apache.org