HTTPCLIENT-1882: reset authentication state on I/O or runtime error for connection based authentication schemes (such as NTLM)

This commit is contained in:
Oleg Kalnichevski 2018-07-04 14:40:14 +02:00
parent ec22a46866
commit fd952c8654
5 changed files with 36 additions and 19 deletions

View File

@ -74,6 +74,13 @@ public AuthScheme getAuthScheme() {
return this.authScheme;
}
/**
* Returns {@code true} if the actual authentication scheme is connection based.
*/
public boolean isConnectionBased() {
return this.authScheme != null && this.authScheme.isConnectionBased();
}
/**
* Resets the auth state with {@link AuthScheme} and clears auth options.
*

View File

@ -193,14 +193,12 @@ public AsyncDataConsumer handleResponse(
public void completed() {
if (!execRuntime.isConnected()) {
if (proxyAuthExchange.getState() == AuthExchange.State.SUCCESS
&& proxyAuthExchange.getAuthScheme() != null
&& proxyAuthExchange.getAuthScheme().isConnectionBased()) {
&& proxyAuthExchange.isConnectionBased()) {
log.debug("Resetting proxy auth state");
proxyAuthExchange.reset();
}
if (targetAuthExchange.getState() == AuthExchange.State.SUCCESS
&& targetAuthExchange.getAuthScheme() != null
&& targetAuthExchange.getAuthScheme().isConnectionBased()) {
&& targetAuthExchange.isConnectionBased()) {
log.debug("Resetting target auth state");
targetAuthExchange.reset();
}
@ -233,6 +231,14 @@ public void completed() {
@Override
public void failed(final Exception cause) {
if (cause instanceof IOException || cause instanceof RuntimeException) {
if (proxyAuthExchange.isConnectionBased()) {
proxyAuthExchange.reset();
}
if (targetAuthExchange.isConnectionBased()) {
targetAuthExchange.reset();
}
}
asyncExecCallback.failed(cause);
}

View File

@ -37,7 +37,6 @@
import org.apache.hc.client5.http.async.AsyncExecChain;
import org.apache.hc.client5.http.async.AsyncExecChainHandler;
import org.apache.hc.client5.http.auth.AuthExchange;
import org.apache.hc.client5.http.auth.AuthScheme;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.protocol.RedirectLocations;
@ -153,8 +152,7 @@ public AsyncDataConsumer handleResponse(
targetAuthExchange.reset();
if (currentRoute.getProxyHost() != null) {
final AuthExchange proxyAuthExchange = clientContext.getAuthExchange(currentRoute.getProxyHost());
final AuthScheme authScheme = proxyAuthExchange.getAuthScheme();
if (authScheme != null && authScheme.isConnectionBased()) {
if (proxyAuthExchange.isConnectionBased()) {
log.debug("Resetting proxy auth state");
proxyAuthExchange.reset();
}

View File

@ -109,9 +109,12 @@ public ClassicHttpResponse execute(
final HttpClientContext context = scope.clientContext;
final ExecRuntime execRuntime = scope.execRuntime;
final HttpHost target = route.getTargetHost();
final HttpHost proxy = route.getProxyHost();
final AuthExchange targetAuthExchange = context.getAuthExchange(target);
final AuthExchange proxyAuthExchange = proxy != null ? context.getAuthExchange(proxy) : new AuthExchange();
try {
final HttpHost target = route.getTargetHost();
final HttpHost proxy = route.getProxyHost();
if (proxy != null && !route.isTunnelled()) {
try {
URI uri = request.getUri();
@ -134,8 +137,6 @@ public ClassicHttpResponse execute(
}
}
final AuthExchange targetAuthExchange = context.getAuthExchange(target);
final AuthExchange proxyAuthExchange = proxy != null ? context.getAuthExchange(proxy) : new AuthExchange();
for (;;) {
@ -180,14 +181,12 @@ public ClassicHttpResponse execute(
} else {
execRuntime.disconnect();
if (proxyAuthExchange.getState() == AuthExchange.State.SUCCESS
&& proxyAuthExchange.getAuthScheme() != null
&& proxyAuthExchange.getAuthScheme().isConnectionBased()) {
&& proxyAuthExchange.isConnectionBased()) {
log.debug("Resetting proxy auth state");
proxyAuthExchange.reset();
}
if (targetAuthExchange.getState() == AuthExchange.State.SUCCESS
&& targetAuthExchange.getAuthScheme() != null
&& targetAuthExchange.getAuthScheme().isConnectionBased()) {
&& targetAuthExchange.isConnectionBased()) {
log.debug("Resetting target auth state");
targetAuthExchange.reset();
}
@ -202,9 +201,18 @@ public ClassicHttpResponse execute(
return response;
}
}
} catch (final RuntimeException | HttpException | IOException ex) {
} catch (final HttpException ex) {
execRuntime.discardConnection();
throw ex;
} catch (final RuntimeException | IOException ex) {
execRuntime.discardConnection();
if (proxyAuthExchange.isConnectionBased()) {
proxyAuthExchange.reset();
}
if (targetAuthExchange.isConnectionBased()) {
targetAuthExchange.reset();
}
throw ex;
}
}

View File

@ -35,7 +35,6 @@
import org.apache.hc.client5.http.RedirectException;
import org.apache.hc.client5.http.StandardMethods;
import org.apache.hc.client5.http.auth.AuthExchange;
import org.apache.hc.client5.http.auth.AuthScheme;
import org.apache.hc.client5.http.classic.ExecChain;
import org.apache.hc.client5.http.classic.ExecChainHandler;
import org.apache.hc.client5.http.classic.methods.HttpGet;
@ -170,8 +169,7 @@ public ClassicHttpResponse execute(
targetAuthExchange.reset();
if (currentRoute.getProxyHost() != null) {
final AuthExchange proxyAuthExchange = context.getAuthExchange(currentRoute.getProxyHost());
final AuthScheme authScheme = proxyAuthExchange.getAuthScheme();
if (authScheme != null && authScheme.isConnectionBased()) {
if (proxyAuthExchange.isConnectionBased()) {
this.log.debug("Resetting proxy auth state");
proxyAuthExchange.reset();
}