You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2021/09/26 09:31:43 UTC

[httpcomponents-client] 01/03: Refactored AuthCache keeping logic into a separate utility class

This is an automated email from the ASF dual-hosted git repository.

olegk pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/httpcomponents-client.git

commit 9555dbf40d6d30c728355e00b85c22efbe9adf31
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Sat Sep 25 18:52:51 2021 +0200

    Refactored AuthCache keeping logic into a separate utility class
---
 .../client5/http/impl/async/AsyncConnectExec.java  |  33 ++++-
 .../client5/http/impl/async/AsyncProtocolExec.java |  82 +++++++++---
 .../http/impl/async/H2AsyncClientBuilder.java      |  15 ++-
 .../http/impl/async/HttpAsyncClientBuilder.java    |  15 ++-
 .../hc/client5/http/impl/auth/AuthCacheKeeper.java | 140 +++++++++++++++++++++
 .../client5/http/impl/auth/HttpAuthenticator.java  |  52 +-------
 .../hc/client5/http/impl/classic/ConnectExec.java  |  43 +++++--
 .../http/impl/classic/HttpClientBuilder.java       |  15 ++-
 .../hc/client5/http/impl/classic/ProtocolExec.java |  63 ++++++++--
 .../hc/client5/http/protocol/RequestAuthCache.java |  21 ++--
 .../http/impl/auth/TestHttpAuthenticator.java      |  13 --
 .../client5/http/impl/classic/TestConnectExec.java |   2 +-
 .../http/impl/classic/TestProtocolExec.java        |   2 +-
 13 files changed, 362 insertions(+), 134 deletions(-)

diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncConnectExec.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncConnectExec.java
index b0288c7..4f83962 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncConnectExec.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncConnectExec.java
@@ -33,6 +33,7 @@ import java.io.InterruptedIOException;
 import org.apache.hc.client5.http.AuthenticationStrategy;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.RouteTracker;
+import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.async.AsyncExecCallback;
 import org.apache.hc.client5.http.async.AsyncExecChain;
 import org.apache.hc.client5.http.async.AsyncExecChainHandler;
@@ -41,6 +42,7 @@ import org.apache.hc.client5.http.auth.AuthExchange;
 import org.apache.hc.client5.http.auth.ChallengeType;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.TunnelRefusedException;
+import org.apache.hc.client5.http.impl.auth.AuthCacheKeeper;
 import org.apache.hc.client5.http.impl.auth.HttpAuthenticator;
 import org.apache.hc.client5.http.impl.routing.BasicRouteDirector;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
@@ -84,17 +86,21 @@ public final class AsyncConnectExec implements AsyncExecChainHandler {
     private final HttpProcessor proxyHttpProcessor;
     private final AuthenticationStrategy proxyAuthStrategy;
     private final HttpAuthenticator authenticator;
+    private final AuthCacheKeeper authCacheKeeper;
     private final HttpRouteDirector routeDirector;
 
     public AsyncConnectExec(
             final HttpProcessor proxyHttpProcessor,
-            final AuthenticationStrategy proxyAuthStrategy) {
+            final AuthenticationStrategy proxyAuthStrategy,
+            final SchemePortResolver schemePortResolver,
+            final boolean authCachingDisabled) {
         Args.notNull(proxyHttpProcessor, "Proxy HTTP processor");
         Args.notNull(proxyAuthStrategy, "Proxy authentication strategy");
         this.proxyHttpProcessor = proxyHttpProcessor;
         this.proxyAuthStrategy  = proxyAuthStrategy;
-        this.authenticator      = new HttpAuthenticator(LOG);
-        this.routeDirector      = new BasicRouteDirector();
+        this.authenticator = new HttpAuthenticator();
+        this.authCacheKeeper = authCachingDisabled ? null : new AuthCacheKeeper(schemePortResolver);
+        this.routeDirector = new BasicRouteDirector();
     }
 
     static class State {
@@ -372,6 +378,10 @@ public final class AsyncConnectExec implements AsyncExecChainHandler {
 
         final AuthExchange proxyAuthExchange = proxy != null ? clientContext.getAuthExchange(proxy) : new AuthExchange();
 
+        if (authCacheKeeper != null) {
+            authCacheKeeper.loadPreemptively(proxy, proxyAuthExchange, clientContext);
+        }
+
         final HttpRequest connect = new BasicHttpRequest(Method.CONNECT, nextHop, nextHop.toHostString());
         connect.setVersion(HttpVersion.HTTP_1_1);
 
@@ -431,9 +441,24 @@ public final class AsyncConnectExec implements AsyncExecChainHandler {
         final RequestConfig config = context.getRequestConfig();
         if (config.isAuthenticationEnabled()) {
             final boolean proxyAuthRequested = authenticator.isChallenged(proxy, ChallengeType.PROXY, response, proxyAuthExchange, context);
+
+            if (authCacheKeeper != null) {
+                if (proxyAuthRequested) {
+                    authCacheKeeper.updateOnChallenge(proxy, proxyAuthExchange, context);
+                } else {
+                    authCacheKeeper.updateOnNoChallenge(proxy, proxyAuthExchange, context);
+                }
+            }
+
             if (proxyAuthRequested) {
-                return authenticator.updateAuthState(proxy, ChallengeType.PROXY, response,
+                final boolean updated = authenticator.updateAuthState(proxy, ChallengeType.PROXY, response,
                         proxyAuthStrategy, proxyAuthExchange, context);
+
+                if (authCacheKeeper != null) {
+                    authCacheKeeper.updateOnResponse(proxy, proxyAuthExchange, context);
+                }
+
+                return updated;
             }
         }
         return false;
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncProtocolExec.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncProtocolExec.java
index 880d9e5..4fe3637 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncProtocolExec.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/AsyncProtocolExec.java
@@ -32,6 +32,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
 
 import org.apache.hc.client5.http.AuthenticationStrategy;
 import org.apache.hc.client5.http.HttpRoute;
+import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.async.AsyncExecCallback;
 import org.apache.hc.client5.http.async.AsyncExecChain;
 import org.apache.hc.client5.http.async.AsyncExecChainHandler;
@@ -42,6 +43,7 @@ import org.apache.hc.client5.http.auth.CredentialsProvider;
 import org.apache.hc.client5.http.auth.CredentialsStore;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.AuthSupport;
+import org.apache.hc.client5.http.impl.auth.AuthCacheKeeper;
 import org.apache.hc.client5.http.impl.auth.HttpAuthenticator;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.core5.annotation.Contract;
@@ -87,15 +89,19 @@ public final class AsyncProtocolExec implements AsyncExecChainHandler {
     private final AuthenticationStrategy targetAuthStrategy;
     private final AuthenticationStrategy proxyAuthStrategy;
     private final HttpAuthenticator authenticator;
+    private final AuthCacheKeeper authCacheKeeper;
 
     AsyncProtocolExec(
             final HttpProcessor httpProcessor,
             final AuthenticationStrategy targetAuthStrategy,
-            final AuthenticationStrategy proxyAuthStrategy) {
+            final AuthenticationStrategy proxyAuthStrategy,
+            final SchemePortResolver schemePortResolver,
+            final boolean authCachingDisabled) {
         this.httpProcessor = Args.notNull(httpProcessor, "HTTP protocol processor");
         this.targetAuthStrategy = Args.notNull(targetAuthStrategy, "Target authentication strategy");
         this.proxyAuthStrategy = Args.notNull(proxyAuthStrategy, "Proxy authentication strategy");
-        this.authenticator = new HttpAuthenticator(LOG);
+        this.authenticator = new HttpAuthenticator();
+        this.authCacheKeeper = authCachingDisabled ? null : new AuthCacheKeeper(schemePortResolver);
     }
 
     @Override
@@ -141,11 +147,26 @@ public final class AsyncProtocolExec implements AsyncExecChainHandler {
             AuthSupport.extractFromAuthority(request.getScheme(), authority, (CredentialsStore) credsProvider);
         }
 
+        final HttpHost target = new HttpHost(request.getScheme(), request.getAuthority());
+        final AuthExchange targetAuthExchange = clientContext.getAuthExchange(target);
+        final AuthExchange proxyAuthExchange = proxy != null ? clientContext.getAuthExchange(proxy) : new AuthExchange();
+
+        if (authCacheKeeper != null) {
+            authCacheKeeper.loadPreemptively(target, targetAuthExchange, clientContext);
+            if (proxy != null) {
+                authCacheKeeper.loadPreemptively(proxy, proxyAuthExchange, clientContext);
+            }
+        }
+
         final AtomicBoolean challenged = new AtomicBoolean(false);
-        internalExecute(challenged, request, entityProducer, scope, chain, asyncExecCallback);
+        internalExecute(target, targetAuthExchange, proxyAuthExchange,
+                challenged, request, entityProducer, scope, chain, asyncExecCallback);
     }
 
     private void internalExecute(
+            final HttpHost target,
+            final AuthExchange targetAuthExchange,
+            final AuthExchange proxyAuthExchange,
             final AtomicBoolean challenged,
             final HttpRequest request,
             final AsyncEntityProducer entityProducer,
@@ -158,10 +179,6 @@ public final class AsyncProtocolExec implements AsyncExecChainHandler {
         final AsyncExecRuntime execRuntime = scope.execRuntime;
 
         final HttpHost proxy = route.getProxyHost();
-        final HttpHost target = new HttpHost(request.getScheme(), request.getAuthority());
-
-        final AuthExchange targetAuthExchange = clientContext.getAuthExchange(target);
-        final AuthExchange proxyAuthExchange = proxy != null ? clientContext.getAuthExchange(proxy) : new AuthExchange();
 
         clientContext.setAttribute(HttpClientContext.HTTP_ROUTE, route);
         clientContext.setAttribute(HttpCoreContext.HTTP_REQUEST, request);
@@ -194,7 +211,13 @@ public final class AsyncProtocolExec implements AsyncExecChainHandler {
                     // Do not perform authentication for TRACE request
                     return asyncExecCallback.handleResponse(response, entityDetails);
                 }
-                if (needAuthentication(targetAuthExchange, proxyAuthExchange, route, request, response, clientContext)) {
+                if (needAuthentication(
+                        targetAuthExchange,
+                        proxyAuthExchange,
+                        proxy != null ? proxy : target,
+                        target,
+                        response,
+                        clientContext)) {
                     challenged.set(true);
                     return null;
                 }
@@ -244,7 +267,8 @@ public final class AsyncProtocolExec implements AsyncExecChainHandler {
                             if (entityProducer != null) {
                                 entityProducer.releaseResources();
                             }
-                            internalExecute(challenged, request, entityProducer, scope, chain, asyncExecCallback);
+                            internalExecute(target, targetAuthExchange, proxyAuthExchange,
+                                    challenged, request, entityProducer, scope, chain, asyncExecCallback);
                         } catch (final HttpException | IOException ex) {
                             asyncExecCallback.failed(ex);
                         }
@@ -272,31 +296,53 @@ public final class AsyncProtocolExec implements AsyncExecChainHandler {
     private boolean needAuthentication(
             final AuthExchange targetAuthExchange,
             final AuthExchange proxyAuthExchange,
-            final HttpRoute route,
-            final HttpRequest request,
+            final HttpHost proxy,
+            final HttpHost target,
             final HttpResponse response,
             final HttpClientContext context) {
         final RequestConfig config = context.getRequestConfig();
         if (config.isAuthenticationEnabled()) {
-            final HttpHost target = AuthSupport.resolveAuthTarget(request, route);
             final boolean targetAuthRequested = authenticator.isChallenged(
                     target, ChallengeType.TARGET, response, targetAuthExchange, context);
 
-            HttpHost proxy = route.getProxyHost();
-            // if proxy is not set use target host instead
-            if (proxy == null) {
-                proxy = route.getTargetHost();
+            if (authCacheKeeper != null) {
+                if (targetAuthRequested) {
+                    authCacheKeeper.updateOnChallenge(target, targetAuthExchange, context);
+                } else {
+                    authCacheKeeper.updateOnNoChallenge(target, targetAuthExchange, context);
+                }
             }
+
             final boolean proxyAuthRequested = authenticator.isChallenged(
                     proxy, ChallengeType.PROXY, response, proxyAuthExchange, context);
 
+            if (authCacheKeeper != null) {
+                if (proxyAuthRequested) {
+                    authCacheKeeper.updateOnChallenge(proxy, proxyAuthExchange, context);
+                } else {
+                    authCacheKeeper.updateOnNoChallenge(proxy, proxyAuthExchange, context);
+                }
+            }
+
             if (targetAuthRequested) {
-                return authenticator.updateAuthState(target, ChallengeType.TARGET, response,
+                final boolean updated = authenticator.updateAuthState(target, ChallengeType.TARGET, response,
                         targetAuthStrategy, targetAuthExchange, context);
+
+                if (authCacheKeeper != null) {
+                    authCacheKeeper.updateOnResponse(target, targetAuthExchange, context);
+                }
+
+                return updated;
             }
             if (proxyAuthRequested) {
-                return authenticator.updateAuthState(proxy, ChallengeType.PROXY, response,
+                final boolean updated = authenticator.updateAuthState(proxy, ChallengeType.PROXY, response,
                         proxyAuthStrategy, proxyAuthExchange, context);
+
+                if (authCacheKeeper != null) {
+                    authCacheKeeper.updateOnResponse(proxy, proxyAuthExchange, context);
+                }
+
+                return updated;
             }
         }
         return false;
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
index 494e925..098acdd 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/H2AsyncClientBuilder.java
@@ -67,7 +67,6 @@ import org.apache.hc.client5.http.impl.nio.MultihomeConnectionInitiator;
 import org.apache.hc.client5.http.impl.routing.DefaultRoutePlanner;
 import org.apache.hc.client5.http.protocol.RedirectStrategy;
 import org.apache.hc.client5.http.protocol.RequestAddCookies;
-import org.apache.hc.client5.http.protocol.RequestAuthCache;
 import org.apache.hc.client5.http.protocol.RequestDefaultHeaders;
 import org.apache.hc.client5.http.protocol.RequestExpectContinue;
 import org.apache.hc.client5.http.protocol.ResponseProcessCookies;
@@ -638,7 +637,9 @@ public class H2AsyncClientBuilder {
         execChainDefinition.addFirst(
                 new AsyncConnectExec(
                         new DefaultHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
-                        proxyAuthStrategyCopy),
+                        proxyAuthStrategyCopy,
+                        schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE,
+                        authCachingDisabled),
                 ChainElement.CONNECT.name());
 
         final HttpProcessorBuilder b = HttpProcessorBuilder.create();
@@ -663,9 +664,6 @@ public class H2AsyncClientBuilder {
         if (!cookieManagementDisabled) {
             b.add(new RequestAddCookies());
         }
-        if (!authCachingDisabled) {
-            b.add(new RequestAuthCache());
-        }
         if (!cookieManagementDisabled) {
             b.add(new ResponseProcessCookies());
         }
@@ -686,7 +684,12 @@ public class H2AsyncClientBuilder {
 
         final HttpProcessor httpProcessor = b.build();
         execChainDefinition.addFirst(
-                new AsyncProtocolExec(httpProcessor, targetAuthStrategyCopy, proxyAuthStrategyCopy),
+                new AsyncProtocolExec(
+                        httpProcessor,
+                        targetAuthStrategyCopy,
+                        proxyAuthStrategyCopy,
+                        schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE,
+                        authCachingDisabled),
                 ChainElement.PROTOCOL.name());
 
         // Add request retry executor, if not disabled
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
index 44a6759..6127ce0 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/async/HttpAsyncClientBuilder.java
@@ -75,7 +75,6 @@ import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner;
 import org.apache.hc.client5.http.nio.AsyncClientConnectionManager;
 import org.apache.hc.client5.http.protocol.RedirectStrategy;
 import org.apache.hc.client5.http.protocol.RequestAddCookies;
-import org.apache.hc.client5.http.protocol.RequestAuthCache;
 import org.apache.hc.client5.http.protocol.RequestDefaultHeaders;
 import org.apache.hc.client5.http.protocol.RequestExpectContinue;
 import org.apache.hc.client5.http.protocol.ResponseProcessCookies;
@@ -778,7 +777,9 @@ public class HttpAsyncClientBuilder {
         execChainDefinition.addFirst(
                 new AsyncConnectExec(
                         new DefaultHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
-                        proxyAuthStrategyCopy),
+                        proxyAuthStrategyCopy,
+                        schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE,
+                        authCachingDisabled),
                 ChainElement.CONNECT.name());
 
         final HttpProcessorBuilder b = HttpProcessorBuilder.create();
@@ -803,9 +804,6 @@ public class HttpAsyncClientBuilder {
         if (!cookieManagementDisabled) {
             b.add(new RequestAddCookies());
         }
-        if (!authCachingDisabled) {
-            b.add(new RequestAuthCache());
-        }
         if (!cookieManagementDisabled) {
             b.add(new ResponseProcessCookies());
         }
@@ -826,7 +824,12 @@ public class HttpAsyncClientBuilder {
 
         final HttpProcessor httpProcessor = b.build();
         execChainDefinition.addFirst(
-                new AsyncProtocolExec(httpProcessor, targetAuthStrategyCopy, proxyAuthStrategyCopy),
+                new AsyncProtocolExec(
+                        httpProcessor,
+                        targetAuthStrategyCopy,
+                        proxyAuthStrategyCopy,
+                        schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE,
+                        authCachingDisabled),
                 ChainElement.PROTOCOL.name());
 
         // Add request retry executor, if not disabled
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/AuthCacheKeeper.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/AuthCacheKeeper.java
new file mode 100644
index 0000000..01f959a
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/AuthCacheKeeper.java
@@ -0,0 +1,140 @@
+/*
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.hc.client5.http.impl.auth;
+
+import org.apache.hc.client5.http.SchemePortResolver;
+import org.apache.hc.client5.http.auth.AuthCache;
+import org.apache.hc.client5.http.auth.AuthExchange;
+import org.apache.hc.client5.http.auth.AuthScheme;
+import org.apache.hc.client5.http.auth.AuthStateCacheable;
+import org.apache.hc.client5.http.protocol.HttpClientContext;
+import org.apache.hc.core5.annotation.Contract;
+import org.apache.hc.core5.annotation.Internal;
+import org.apache.hc.core5.annotation.ThreadingBehavior;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class that implements commons aspects of the client side authentication cache keeping.
+ *
+ * @since 5.2
+ */
+@Internal
+@Contract(threading = ThreadingBehavior.STATELESS)
+public final class AuthCacheKeeper {
+
+    private static final Logger LOG = LoggerFactory.getLogger(AuthCacheKeeper.class);
+
+    private final SchemePortResolver schemePortResolver;
+
+    public AuthCacheKeeper(final SchemePortResolver schemePortResolver) {
+        this.schemePortResolver = schemePortResolver;
+    }
+
+    public void updateOnChallenge(final HttpHost host,
+                                  final AuthExchange authExchange,
+                                  final HttpContext context) {
+        clearCache(host, HttpClientContext.adapt(context));
+    }
+
+    public void updateOnNoChallenge(final HttpHost host,
+                                    final AuthExchange authExchange,
+                                    final HttpContext context) {
+        if (authExchange.getState() == AuthExchange.State.SUCCESS) {
+            updateCache(host, authExchange.getAuthScheme(), HttpClientContext.adapt(context));
+        }
+    }
+
+    public void updateOnResponse(final HttpHost host,
+                                 final AuthExchange authExchange,
+                                 final HttpContext context) {
+        if (authExchange.getState() == AuthExchange.State.FAILURE) {
+            clearCache(host, HttpClientContext.adapt(context));
+        }
+    }
+
+    public void loadPreemptively(final HttpHost host,
+                                 final AuthExchange authExchange,
+                                 final HttpContext context) {
+        if (authExchange.getState() == AuthExchange.State.UNCHALLENGED) {
+            final AuthScheme authScheme = loadFromCache(host, HttpClientContext.adapt(context));
+            if (authScheme != null) {
+                authExchange.select(authScheme);
+            }
+        }
+    }
+
+    private AuthScheme loadFromCache(final HttpHost host,
+                                     final HttpClientContext clientContext) {
+        final AuthCache authCache = clientContext.getAuthCache();
+        if (authCache != null) {
+            final AuthScheme authScheme = authCache.get(host);
+            if (authScheme != null) {
+                if (LOG.isDebugEnabled()) {
+                    final String exchangeId = clientContext.getExchangeId();
+                    LOG.debug("{} Re-using cached '{}' auth scheme for {}", exchangeId, authScheme.getName(), host);
+                }
+                return authScheme;
+            }
+        }
+        return null;
+    }
+
+    private void updateCache(final HttpHost host,
+                             final AuthScheme authScheme,
+                             final HttpClientContext clientContext) {
+        final boolean cacheable = authScheme.getClass().getAnnotation(AuthStateCacheable.class) != null;
+        if (cacheable) {
+            AuthCache authCache = clientContext.getAuthCache();
+            if (authCache == null) {
+                authCache = new BasicAuthCache(schemePortResolver);
+                clientContext.setAuthCache(authCache);
+            }
+            if (LOG.isDebugEnabled()) {
+                final String exchangeId = clientContext.getExchangeId();
+                LOG.debug("{} Caching '{}' auth scheme for {}", exchangeId, authScheme.getName(), host);
+            }
+            authCache.put(host, authScheme);
+        }
+    }
+
+    private void clearCache(final HttpHost host,
+                            final HttpClientContext clientContext) {
+        final AuthCache authCache = clientContext.getAuthCache();
+        if (authCache != null) {
+            if (LOG.isDebugEnabled()) {
+                final String exchangeId = clientContext.getExchangeId();
+                LOG.debug("{} Clearing cached auth scheme for {}", exchangeId, host);
+            }
+            authCache.remove(host);
+        }
+    }
+
+}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/HttpAuthenticator.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/HttpAuthenticator.java
index 7987402..0a5592b 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/HttpAuthenticator.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/HttpAuthenticator.java
@@ -35,18 +35,15 @@ import java.util.Map;
 import java.util.Queue;
 
 import org.apache.hc.client5.http.AuthenticationStrategy;
-import org.apache.hc.client5.http.auth.AuthCache;
 import org.apache.hc.client5.http.auth.AuthChallenge;
 import org.apache.hc.client5.http.auth.AuthExchange;
 import org.apache.hc.client5.http.auth.AuthScheme;
-import org.apache.hc.client5.http.auth.AuthStateCacheable;
 import org.apache.hc.client5.http.auth.AuthenticationException;
 import org.apache.hc.client5.http.auth.ChallengeType;
 import org.apache.hc.client5.http.auth.CredentialsProvider;
 import org.apache.hc.client5.http.auth.MalformedChallengeException;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.core5.annotation.Contract;
-import org.apache.hc.core5.annotation.Internal;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.FormattedHeader;
 import org.apache.hc.core5.http.Header;
@@ -66,6 +63,9 @@ import org.slf4j.LoggerFactory;
 
 /**
  * Utility class that implements commons aspects of the client side HTTP authentication.
+ * <p>
+ * Please note that since version 5.2 this class no longer updated the authentication cache
+ * bound to the execution context.
  *
  * @since 4.3
  */
@@ -77,15 +77,9 @@ public final class HttpAuthenticator {
     private final Logger log;
     private final AuthChallengeParser parser;
 
-    @Internal
-    public HttpAuthenticator(final Logger log) {
-        super();
-        this.log = log != null ? log : DEFAULT_LOGGER;
-        this.parser = new AuthChallengeParser();
-    }
-
     public HttpAuthenticator() {
-        this(null);
+        this.log = DEFAULT_LOGGER;
+        this.parser = new AuthChallengeParser();
     }
 
     /**
@@ -124,9 +118,6 @@ public final class HttpAuthenticator {
             if (log.isDebugEnabled()) {
                 log.debug("{} Authentication required", exchangeId);
             }
-            if (authExchange.getState() == AuthExchange.State.SUCCESS) {
-                clearCache(host, clientContext);
-            }
             return true;
         }
         switch (authExchange.getState()) {
@@ -136,7 +127,6 @@ public final class HttpAuthenticator {
                 log.debug("{} Authentication succeeded", exchangeId);
             }
             authExchange.setState(AuthExchange.State.SUCCESS);
-            updateCache(host, authExchange.getAuthScheme(), clientContext);
             break;
         case SUCCESS:
             break;
@@ -213,7 +203,6 @@ public final class HttpAuthenticator {
             if (log.isDebugEnabled()) {
                 log.debug("{} Response contains no valid authentication challenges", exchangeId);
             }
-            clearCache(host, clientContext);
             authExchange.reset();
             return false;
         }
@@ -242,15 +231,14 @@ public final class HttpAuthenticator {
                             if (log.isWarnEnabled()) {
                                 log.warn("{} {}", exchangeId, ex.getMessage());
                             }
-                            clearCache(host, clientContext);
                             authExchange.reset();
+                            authExchange.setState(AuthExchange.State.FAILURE);
                             return false;
                         }
                         if (authScheme.isChallengeComplete()) {
                             if (log.isDebugEnabled()) {
                                 log.debug("{} Authentication failed", exchangeId);
                             }
-                            clearCache(host, clientContext);
                             authExchange.reset();
                             authExchange.setState(AuthExchange.State.FAILURE);
                             return false;
@@ -376,32 +364,4 @@ public final class HttpAuthenticator {
         }
     }
 
-    private void updateCache(final HttpHost host, final AuthScheme authScheme, final HttpClientContext clientContext) {
-        final boolean cacheable = authScheme.getClass().getAnnotation(AuthStateCacheable.class) != null;
-        if (cacheable) {
-            AuthCache authCache = clientContext.getAuthCache();
-            if (authCache == null) {
-                authCache = new BasicAuthCache();
-                clientContext.setAuthCache(authCache);
-            }
-            if (log.isDebugEnabled()) {
-                final String exchangeId = clientContext.getExchangeId();
-                log.debug("{} Caching '{}' auth scheme for {}", exchangeId, authScheme.getName(), host);
-            }
-            authCache.put(host, authScheme);
-        }
-    }
-
-    private void clearCache(final HttpHost host, final HttpClientContext clientContext) {
-
-        final AuthCache authCache = clientContext.getAuthCache();
-        if (authCache != null) {
-            if (log.isDebugEnabled()) {
-                final String exchangeId = clientContext.getExchangeId();
-                log.debug("{} Clearing cached auth scheme for {}", exchangeId, host);
-            }
-            authCache.remove(host);
-        }
-    }
-
 }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ConnectExec.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ConnectExec.java
index 357915f..5b80e21 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ConnectExec.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ConnectExec.java
@@ -32,6 +32,7 @@ import java.io.IOException;
 import org.apache.hc.client5.http.AuthenticationStrategy;
 import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.RouteTracker;
+import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.auth.AuthExchange;
 import org.apache.hc.client5.http.auth.ChallengeType;
 import org.apache.hc.client5.http.classic.ExecChain;
@@ -39,6 +40,7 @@ import org.apache.hc.client5.http.classic.ExecChainHandler;
 import org.apache.hc.client5.http.classic.ExecRuntime;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.TunnelRefusedException;
+import org.apache.hc.client5.http.impl.auth.AuthCacheKeeper;
 import org.apache.hc.client5.http.impl.auth.HttpAuthenticator;
 import org.apache.hc.client5.http.impl.routing.BasicRouteDirector;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
@@ -82,20 +84,24 @@ public final class ConnectExec implements ExecChainHandler {
     private final HttpProcessor proxyHttpProcessor;
     private final AuthenticationStrategy proxyAuthStrategy;
     private final HttpAuthenticator authenticator;
+    private final AuthCacheKeeper authCacheKeeper;
     private final HttpRouteDirector routeDirector;
 
     public ConnectExec(
             final ConnectionReuseStrategy reuseStrategy,
             final HttpProcessor proxyHttpProcessor,
-            final AuthenticationStrategy proxyAuthStrategy) {
+            final AuthenticationStrategy proxyAuthStrategy,
+            final SchemePortResolver schemePortResolver,
+            final boolean authCachingDisabled) {
         Args.notNull(reuseStrategy, "Connection reuse strategy");
         Args.notNull(proxyHttpProcessor, "Proxy HTTP processor");
         Args.notNull(proxyAuthStrategy, "Proxy authentication strategy");
-        this.reuseStrategy      = reuseStrategy;
+        this.reuseStrategy = reuseStrategy;
         this.proxyHttpProcessor = proxyHttpProcessor;
-        this.proxyAuthStrategy  = proxyAuthStrategy;
-        this.authenticator      = new HttpAuthenticator(LOG);
-        this.routeDirector      = new BasicRouteDirector();
+        this.proxyAuthStrategy = proxyAuthStrategy;
+        this.authenticator = new HttpAuthenticator();
+        this.authCacheKeeper = authCachingDisabled ? null : new AuthCacheKeeper(schemePortResolver);
+        this.routeDirector = new BasicRouteDirector();
     }
 
     @Override
@@ -207,6 +213,11 @@ public final class ConnectExec implements ExecChainHandler {
         final HttpHost target = route.getTargetHost();
         final HttpHost proxy = route.getProxyHost();
         final AuthExchange proxyAuthExchange = context.getAuthExchange(proxy);
+
+        if (authCacheKeeper != null) {
+            authCacheKeeper.loadPreemptively(proxy, proxyAuthExchange, context);
+        }
+
         ClassicHttpResponse response = null;
 
         final String authority = target.toHostString();
@@ -239,10 +250,24 @@ public final class ConnectExec implements ExecChainHandler {
             }
 
             if (config.isAuthenticationEnabled()) {
-                if (this.authenticator.isChallenged(proxy, ChallengeType.PROXY, response,
-                        proxyAuthExchange, context)) {
-                    if (this.authenticator.updateAuthState(proxy, ChallengeType.PROXY, response,
-                            this.proxyAuthStrategy, proxyAuthExchange, context)) {
+                final boolean proxyAuthRequested = authenticator.isChallenged(proxy, ChallengeType.PROXY, response, proxyAuthExchange, context);
+
+                if (authCacheKeeper != null) {
+                    if (proxyAuthRequested) {
+                        authCacheKeeper.updateOnChallenge(proxy, proxyAuthExchange, context);
+                    } else {
+                        authCacheKeeper.updateOnNoChallenge(proxy, proxyAuthExchange, context);
+                    }
+                }
+
+                if (proxyAuthRequested) {
+                    final boolean updated = authenticator.updateAuthState(proxy, ChallengeType.PROXY, response,
+                            proxyAuthStrategy, proxyAuthExchange, context);
+
+                    if (authCacheKeeper != null) {
+                        authCacheKeeper.updateOnResponse(proxy, proxyAuthExchange, context);
+                    }
+                    if (updated) {
                         // Retry request
                         response = null;
                     }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java
index 13e7b3b..d40d077 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/HttpClientBuilder.java
@@ -77,7 +77,6 @@ import org.apache.hc.client5.http.impl.routing.SystemDefaultRoutePlanner;
 import org.apache.hc.client5.http.io.HttpClientConnectionManager;
 import org.apache.hc.client5.http.protocol.RedirectStrategy;
 import org.apache.hc.client5.http.protocol.RequestAddCookies;
-import org.apache.hc.client5.http.protocol.RequestAuthCache;
 import org.apache.hc.client5.http.protocol.RequestClientConnControl;
 import org.apache.hc.client5.http.protocol.RequestDefaultHeaders;
 import org.apache.hc.client5.http.protocol.RequestExpectContinue;
@@ -791,7 +790,9 @@ public class HttpClientBuilder {
                 new ConnectExec(
                         reuseStrategyCopy,
                         new DefaultHttpProcessor(new RequestTargetHost(), new RequestUserAgent(userAgentCopy)),
-                        proxyAuthStrategyCopy),
+                        proxyAuthStrategyCopy,
+                        schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE,
+                        authCachingDisabled),
                 ChainElement.CONNECT.name());
 
         final HttpProcessorBuilder b = HttpProcessorBuilder.create();
@@ -819,9 +820,6 @@ public class HttpClientBuilder {
         if (!cookieManagementDisabled) {
             b.add(new RequestAddCookies());
         }
-        if (!authCachingDisabled) {
-            b.add(new RequestAuthCache());
-        }
         if (!cookieManagementDisabled) {
             b.add(new ResponseProcessCookies());
         }
@@ -841,7 +839,12 @@ public class HttpClientBuilder {
         }
         final HttpProcessor httpProcessor = b.build();
         execChainDefinition.addFirst(
-                new ProtocolExec(httpProcessor, targetAuthStrategyCopy, proxyAuthStrategyCopy),
+                new ProtocolExec(
+                        httpProcessor,
+                        targetAuthStrategyCopy,
+                        proxyAuthStrategyCopy,
+                        schemePortResolver != null ? schemePortResolver : DefaultSchemePortResolver.INSTANCE,
+                        authCachingDisabled),
                 ChainElement.PROTOCOL.name());
 
         // Add request retry executor, if not disabled
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ProtocolExec.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ProtocolExec.java
index 14fcbfb..556f7a6 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ProtocolExec.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/classic/ProtocolExec.java
@@ -32,6 +32,7 @@ import java.util.Iterator;
 
 import org.apache.hc.client5.http.AuthenticationStrategy;
 import org.apache.hc.client5.http.HttpRoute;
+import org.apache.hc.client5.http.SchemePortResolver;
 import org.apache.hc.client5.http.auth.AuthExchange;
 import org.apache.hc.client5.http.auth.ChallengeType;
 import org.apache.hc.client5.http.auth.CredentialsProvider;
@@ -41,6 +42,7 @@ import org.apache.hc.client5.http.classic.ExecChainHandler;
 import org.apache.hc.client5.http.classic.ExecRuntime;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.AuthSupport;
+import org.apache.hc.client5.http.impl.auth.AuthCacheKeeper;
 import org.apache.hc.client5.http.impl.auth.HttpAuthenticator;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.core5.annotation.Contract;
@@ -86,15 +88,19 @@ public final class ProtocolExec implements ExecChainHandler {
     private final AuthenticationStrategy targetAuthStrategy;
     private final AuthenticationStrategy proxyAuthStrategy;
     private final HttpAuthenticator authenticator;
+    private final AuthCacheKeeper authCacheKeeper;
 
     public ProtocolExec(
             final HttpProcessor httpProcessor,
             final AuthenticationStrategy targetAuthStrategy,
-            final AuthenticationStrategy proxyAuthStrategy) {
+            final AuthenticationStrategy proxyAuthStrategy,
+            final SchemePortResolver schemePortResolver,
+            final boolean authCachingDisabled) {
         this.httpProcessor = Args.notNull(httpProcessor, "HTTP protocol processor");
         this.targetAuthStrategy = Args.notNull(targetAuthStrategy, "Target authentication strategy");
         this.proxyAuthStrategy = Args.notNull(proxyAuthStrategy, "Proxy authentication strategy");
         this.authenticator = new HttpAuthenticator();
+        this.authCacheKeeper = authCachingDisabled ? null : new AuthCacheKeeper(schemePortResolver);
     }
 
     @Override
@@ -149,6 +155,13 @@ public final class ProtocolExec implements ExecChainHandler {
             final AuthExchange targetAuthExchange = context.getAuthExchange(target);
             final AuthExchange proxyAuthExchange = proxy != null ? context.getAuthExchange(proxy) : new AuthExchange();
 
+            if (authCacheKeeper != null) {
+                authCacheKeeper.loadPreemptively(target, targetAuthExchange, context);
+                if (proxy != null) {
+                    authCacheKeeper.loadPreemptively(proxy, proxyAuthExchange, context);
+                }
+            }
+
             RequestEntityProxy.enhance(request);
 
             for (;;) {
@@ -188,7 +201,13 @@ public final class ProtocolExec implements ExecChainHandler {
                     }
                     return response;
                 }
-                if (needAuthentication(targetAuthExchange, proxyAuthExchange, route, request, response, context)) {
+                if (needAuthentication(
+                        targetAuthExchange,
+                        proxyAuthExchange,
+                        proxy != null ? proxy : target,
+                        target,
+                        response,
+                        context)) {
                     // Make sure the response body is fully consumed, if present
                     final HttpEntity responseEntity = response.getEntity();
                     if (execRuntime.isConnectionReusable()) {
@@ -238,31 +257,53 @@ public final class ProtocolExec implements ExecChainHandler {
     private boolean needAuthentication(
             final AuthExchange targetAuthExchange,
             final AuthExchange proxyAuthExchange,
-            final HttpRoute route,
-            final ClassicHttpRequest request,
+            final HttpHost proxy,
+            final HttpHost target,
             final HttpResponse response,
             final HttpClientContext context) {
         final RequestConfig config = context.getRequestConfig();
         if (config.isAuthenticationEnabled()) {
-            final HttpHost target = AuthSupport.resolveAuthTarget(request, route);
             final boolean targetAuthRequested = authenticator.isChallenged(
                     target, ChallengeType.TARGET, response, targetAuthExchange, context);
 
-            HttpHost proxy = route.getProxyHost();
-            // if proxy is not set use target host instead
-            if (proxy == null) {
-                proxy = route.getTargetHost();
+            if (authCacheKeeper != null) {
+                if (targetAuthRequested) {
+                    authCacheKeeper.updateOnChallenge(target, targetAuthExchange, context);
+                } else {
+                    authCacheKeeper.updateOnNoChallenge(target, targetAuthExchange, context);
+                }
             }
+
             final boolean proxyAuthRequested = authenticator.isChallenged(
                     proxy, ChallengeType.PROXY, response, proxyAuthExchange, context);
 
+            if (authCacheKeeper != null) {
+                if (proxyAuthRequested) {
+                    authCacheKeeper.updateOnChallenge(proxy, proxyAuthExchange, context);
+                } else {
+                    authCacheKeeper.updateOnNoChallenge(proxy, proxyAuthExchange, context);
+                }
+            }
+
             if (targetAuthRequested) {
-                return authenticator.updateAuthState(target, ChallengeType.TARGET, response,
+                final boolean updated = authenticator.updateAuthState(target, ChallengeType.TARGET, response,
                         targetAuthStrategy, targetAuthExchange, context);
+
+                if (authCacheKeeper != null) {
+                    authCacheKeeper.updateOnResponse(target, targetAuthExchange, context);
+                }
+
+                return updated;
             }
             if (proxyAuthRequested) {
-                return authenticator.updateAuthState(proxy, ChallengeType.PROXY, response,
+                final boolean updated = authenticator.updateAuthState(proxy, ChallengeType.PROXY, response,
                         proxyAuthStrategy, proxyAuthExchange, context);
+
+                if (authCacheKeeper != null) {
+                    authCacheKeeper.updateOnResponse(proxy, proxyAuthExchange, context);
+                }
+
+                return updated;
             }
         }
         return false;
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/RequestAuthCache.java b/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/RequestAuthCache.java
index 597bb21..608357d 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/RequestAuthCache.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/protocol/RequestAuthCache.java
@@ -34,6 +34,7 @@ import org.apache.hc.client5.http.auth.AuthCache;
 import org.apache.hc.client5.http.auth.AuthExchange;
 import org.apache.hc.client5.http.auth.AuthScheme;
 import org.apache.hc.client5.http.auth.CredentialsProvider;
+import org.apache.hc.client5.http.impl.RequestSupport;
 import org.apache.hc.core5.annotation.Contract;
 import org.apache.hc.core5.annotation.ThreadingBehavior;
 import org.apache.hc.core5.http.EntityDetails;
@@ -42,7 +43,6 @@ import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpRequest;
 import org.apache.hc.core5.http.HttpRequestInterceptor;
 import org.apache.hc.core5.http.protocol.HttpContext;
-import org.apache.hc.core5.net.URIAuthority;
 import org.apache.hc.core5.util.Args;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -53,7 +53,10 @@ import org.slf4j.LoggerFactory;
  * {@link AuthCache} associated with the given target or proxy host.
  *
  * @since 4.1
+ *
+ * @deprecated Do not use.
  */
+@Deprecated
 @Contract(threading = ThreadingBehavior.STATELESS)
 public class RequestAuthCache implements HttpRequestInterceptor {
 
@@ -96,19 +99,11 @@ public class RequestAuthCache implements HttpRequestInterceptor {
             return;
         }
 
-        final URIAuthority authority = request.getAuthority();
-        final HttpHost target;
-        if (authority != null) {
-            target = new HttpHost(
-                    request.getScheme(),
-                    authority.getHostName(),
-                    authority.getPort() >= 0 ? authority.getPort() : route.getTargetHost().getPort());
-        } else {
-            target = route.getTargetHost();
-        }
+        final HttpHost target = new HttpHost(request.getScheme(), request.getAuthority());
         final AuthExchange targetAuthExchange = clientContext.getAuthExchange(target);
         if (targetAuthExchange.getState() == AuthExchange.State.UNCHALLENGED) {
-            final AuthScheme authScheme = authCache.get(target);
+            final String pathPrefix = RequestSupport.extractPathPrefix(request);
+            final AuthScheme authScheme = authCache.get(target, pathPrefix);
             if (authScheme != null) {
                 if (LOG.isDebugEnabled()) {
                     LOG.debug("{} Re-using cached '{}' auth scheme for {}", exchangeId, authScheme.getName(), target);
@@ -121,7 +116,7 @@ public class RequestAuthCache implements HttpRequestInterceptor {
         if (proxy != null) {
             final AuthExchange proxyAuthExchange = clientContext.getAuthExchange(proxy);
             if (proxyAuthExchange.getState() == AuthExchange.State.UNCHALLENGED) {
-                final AuthScheme authScheme = authCache.get(proxy);
+                final AuthScheme authScheme = authCache.get(proxy, null);
                 if (authScheme != null) {
                     if (LOG.isDebugEnabled()) {
                         LOG.debug("{} Re-using cached '{}' auth scheme for {}", exchangeId, authScheme.getName(), proxy);
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestHttpAuthenticator.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestHttpAuthenticator.java
index fd24894..10e6946 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestHttpAuthenticator.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestHttpAuthenticator.java
@@ -29,7 +29,6 @@ package org.apache.hc.client5.http.impl.auth;
 import java.util.LinkedList;
 import java.util.Queue;
 
-import org.apache.hc.client5.http.auth.AuthCache;
 import org.apache.hc.client5.http.auth.AuthExchange;
 import org.apache.hc.client5.http.auth.AuthScheme;
 import org.apache.hc.client5.http.auth.AuthSchemeFactory;
@@ -80,7 +79,6 @@ public class TestHttpAuthenticator {
     private HttpHost defaultHost;
     private CredentialsProvider credentialsProvider;
     private Lookup<AuthSchemeFactory> authSchemeRegistry;
-    private AuthCache authCache;
     private HttpAuthenticator httpAuthenticator;
 
     @Before
@@ -98,8 +96,6 @@ public class TestHttpAuthenticator {
             .register(StandardAuthScheme.DIGEST, DigestSchemeFactory.INSTANCE)
             .register(StandardAuthScheme.NTLM, NTLMSchemeFactory.INSTANCE).build();
         this.context.setAttribute(HttpClientContext.AUTHSCHEME_REGISTRY, this.authSchemeRegistry);
-        this.authCache = Mockito.mock(AuthCache.class);
-        this.context.setAttribute(HttpClientContext.AUTH_CACHE, this.authCache);
         this.httpAuthenticator = new HttpAuthenticator();
     }
 
@@ -109,7 +105,6 @@ public class TestHttpAuthenticator {
         response.setHeader(HttpHeaders.WWW_AUTHENTICATE, StandardAuthScheme.BASIC + " realm=test");
         Assert.assertTrue(this.httpAuthenticator.isChallenged(
                 this.defaultHost, ChallengeType.TARGET, response, this.authExchange, this.context));
-        Mockito.verifyNoInteractions(this.authCache);
     }
 
     @Test
@@ -122,8 +117,6 @@ public class TestHttpAuthenticator {
 
         Assert.assertTrue(this.httpAuthenticator.isChallenged(
                 this.defaultHost, ChallengeType.TARGET, response, this.authExchange, this.context));
-
-        Mockito.verify(this.authCache).remove(this.defaultHost);
     }
 
     @Test
@@ -144,8 +137,6 @@ public class TestHttpAuthenticator {
         Assert.assertFalse(this.httpAuthenticator.isChallenged(
                 this.defaultHost, ChallengeType.TARGET, response, this.authExchange, this.context));
         Assert.assertEquals(AuthExchange.State.SUCCESS, this.authExchange.getState());
-
-        Mockito.verify(this.authCache).put(this.defaultHost, this.authScheme);
     }
 
     @Test
@@ -157,8 +148,6 @@ public class TestHttpAuthenticator {
         Assert.assertFalse(this.httpAuthenticator.isChallenged(
                 this.defaultHost, ChallengeType.TARGET, response, this.authExchange, this.context));
         Assert.assertEquals(AuthExchange.State.SUCCESS, this.authExchange.getState());
-
-        Mockito.verify(this.authCache).put(this.defaultHost, this.authScheme);
     }
 
     @Test
@@ -269,8 +258,6 @@ public class TestHttpAuthenticator {
                 host, ChallengeType.TARGET, response, authStrategy, this.authExchange, this.context));
 
         Assert.assertEquals(AuthExchange.State.FAILURE, this.authExchange.getState());
-
-        Mockito.verify(this.authCache).remove(host);
     }
 
     @Test
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestConnectExec.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestConnectExec.java
index 730fbd1..1a743bb 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestConnectExec.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestConnectExec.java
@@ -87,7 +87,7 @@ public class TestConnectExec {
 
     @Before
     public void setup() throws Exception {
-        exec = new ConnectExec(reuseStrategy, proxyHttpProcessor, proxyAuthStrategy);
+        exec = new ConnectExec(reuseStrategy, proxyHttpProcessor, proxyAuthStrategy, null, true);
         target = new HttpHost("foo", 80);
         proxy = new HttpHost("bar", 8888);
     }
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestProtocolExec.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestProtocolExec.java
index 3e687cd..e0d78dc 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestProtocolExec.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/classic/TestProtocolExec.java
@@ -89,7 +89,7 @@ public class TestProtocolExec {
 
     @Before
     public void setup() throws Exception {
-        protocolExec = new ProtocolExec(httpProcessor, targetAuthStrategy, proxyAuthStrategy);
+        protocolExec = new ProtocolExec(httpProcessor, targetAuthStrategy, proxyAuthStrategy, null, true);
         target = new HttpHost("foo", 80);
         proxy = new HttpHost("bar", 8888);
     }