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/29 16:08:23 UTC

[httpcomponents-client] 02/11: Added immutable CredentialsProvider implementations and a CredentialsProvider builder; changed test cases and examples to use immutable CredentialsProvider where possible

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 7b47b28d469808c99c89fcaacd78d44ae6b9ac6e
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Thu Sep 23 12:34:27 2021 +0200

    Added immutable CredentialsProvider implementations and a CredentialsProvider builder; changed test cases and examples to use immutable CredentialsProvider where possible
---
 .../AbstractHttpAsyncClientAuthentication.java     |   9 +-
 .../testing/sync/TestClientAuthentication.java     |  31 +++--
 .../sync/TestClientAuthenticationFakeNTLM.java     |  38 +++---
 .../hc/client5/testing/sync/TestSPNegoScheme.java  |  15 +--
 .../http/impl/auth/BasicCredentialsProvider.java   |  41 +------
 ...ntialsProvider.java => CredentialsMatcher.java} |  53 +--------
 .../http/impl/auth/CredentialsProviderBuilder.java | 104 +++++++++++++++++
 .../http/impl/auth/FixedCredentialsProvider.java   |  57 +++++++++
 .../http/impl/auth/SingleCredentialsProvider.java  |  61 ++++++++++
 .../http/examples/AsyncClientAuthentication.java   |  13 +--
 .../http/examples/ClientAuthentication.java        |  13 +--
 .../client5/http/examples/ClientConfiguration.java |   5 +-
 .../ClientPreemptiveDigestAuthentication.java      |  11 +-
 .../http/examples/ClientProxyAuthentication.java   |  18 ++-
 .../http/impl/TestAuthenticationStrategy.java      |  18 ++-
 .../hc/client5/http/impl/auth/TestBasicScheme.java |  15 ++-
 ...Provider.java => TestCredentialsProviders.java} |  24 +++-
 .../client5/http/impl/auth/TestDigestScheme.java   | 129 +++++++++------------
 .../http/impl/auth/TestRequestAuthCache.java       |  10 +-
 .../client5/http/impl/classic/TestConnectExec.java |  15 +--
 .../http/impl/classic/TestProtocolExec.java        |  20 ++--
 21 files changed, 410 insertions(+), 290 deletions(-)

diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncClientAuthentication.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncClientAuthentication.java
index 307b82d..7a0c7e3 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncClientAuthentication.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/async/AbstractHttpAsyncClientAuthentication.java
@@ -48,8 +48,8 @@ import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.DefaultAuthenticationStrategy;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
-import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
 import org.apache.hc.client5.http.impl.auth.BasicScheme;
+import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.client5.testing.BasicTestAuthenticator;
 import org.apache.hc.client5.testing.auth.Authenticator;
@@ -298,11 +298,10 @@ public abstract class AbstractHttpAsyncClientAuthentication<T extends CloseableH
         });
         final HttpHost target = start();
 
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(new AuthScope(null, null, -1, null ,null),
-                new UsernamePasswordCredentials("test", "test".toCharArray()));
         final HttpClientContext context = HttpClientContext.create();
-        context.setCredentialsProvider(credsProvider);
+        context.setCredentialsProvider(CredentialsProviderBuilder.create()
+                        .add(target, "test", "test".toCharArray())
+                .build());
 
         final Future<SimpleHttpResponse> future1 = httpclient.execute(SimpleRequestBuilder.get()
                         .setHttpHost(target)
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientAuthentication.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientAuthentication.java
index 1473062..e443375 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientAuthentication.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientAuthentication.java
@@ -51,9 +51,9 @@ import org.apache.hc.client5.http.classic.methods.HttpPut;
 import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.impl.DefaultAuthenticationStrategy;
 import org.apache.hc.client5.http.impl.auth.BasicAuthCache;
-import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
 import org.apache.hc.client5.http.impl.auth.BasicScheme;
 import org.apache.hc.client5.http.impl.auth.BasicSchemeFactory;
+import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
 import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.client5.testing.BasicTestAuthenticator;
@@ -313,10 +313,9 @@ public class TestClientAuthentication extends LocalServerTestBase {
         final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(new AuthScope(null, null, -1, null ,null),
-                new UsernamePasswordCredentials("test", "test".toCharArray()));
-        context.setCredentialsProvider(credsProvider);
+        context.setCredentialsProvider(CredentialsProviderBuilder.create()
+                .add(target, "test", "test".toCharArray())
+                .build());
 
         final HttpGet httpget = new HttpGet("/");
 
@@ -365,11 +364,10 @@ public class TestClientAuthentication extends LocalServerTestBase {
         });
 
         final TestTargetAuthenticationStrategy authStrategy = new TestTargetAuthenticationStrategy();
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(new AuthScope(target, "this realm", null),
-                new UsernamePasswordCredentials("test", "this".toCharArray()));
-        credsProvider.setCredentials(new AuthScope(target, "that realm", null),
-                new UsernamePasswordCredentials("test", "that".toCharArray()));
+        final CredentialsProvider credsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(target, "this realm", null), "test", "this".toCharArray())
+                .add(new AuthScope(target, "that realm", null), "test", "that".toCharArray())
+                .build();
 
         this.clientBuilder.setTargetAuthenticationStrategy(authStrategy);
         this.httpclient = this.clientBuilder.build();
@@ -519,10 +517,9 @@ public class TestClientAuthentication extends LocalServerTestBase {
         final AuthCache authCache = new BasicAuthCache();
         authCache.put(target, new BasicScheme());
         context.setAuthCache(authCache);
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(new AuthScope(null, null, -1, null ,null),
-                new UsernamePasswordCredentials("test", "stuff".toCharArray()));
-        context.setCredentialsProvider(credsProvider);
+        context.setCredentialsProvider(CredentialsProviderBuilder.create()
+                .add(target, "test", "stuff".toCharArray())
+                .build());
 
         final HttpGet httpget = new HttpGet("/");
         final ClassicHttpResponse response1 = this.httpclient.execute(target, httpget, context);
@@ -587,9 +584,9 @@ public class TestClientAuthentication extends LocalServerTestBase {
                 });
 
         final HttpClientContext context = HttpClientContext.create();
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(new AuthScope(null, null, -1, null ,null),
-                new UsernamePasswordCredentials("test", "test".toCharArray()));
+        final CredentialsProvider credsProvider = CredentialsProviderBuilder.create()
+                .add(target, "test", "test".toCharArray())
+                .build();
         context.setCredentialsProvider(credsProvider);
 
         for (int i = 0; i < 2; i++) {
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientAuthenticationFakeNTLM.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientAuthenticationFakeNTLM.java
index 1ca26a8..f4a3d9e 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientAuthenticationFakeNTLM.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestClientAuthenticationFakeNTLM.java
@@ -28,11 +28,11 @@ package org.apache.hc.client5.testing.sync;
 
 import java.io.IOException;
 
-import org.apache.hc.client5.http.auth.StandardAuthScheme;
-import org.apache.hc.client5.http.auth.AuthScope;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
 import org.apache.hc.client5.http.auth.NTCredentials;
+import org.apache.hc.client5.http.auth.StandardAuthScheme;
 import org.apache.hc.client5.http.classic.methods.HttpGet;
-import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
 import org.apache.hc.client5.http.impl.classic.HttpClients;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.core5.http.ClassicHttpRequest;
@@ -71,9 +71,9 @@ public class TestClientAuthenticationFakeNTLM extends LocalServerTestBase {
 
         final HttpHost target = start();
 
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(new AuthScope(null, null, -1, null ,null),
-                new NTCredentials("test", "test".toCharArray(), null, null));
+        final CredentialsProvider credsProvider = CredentialsProviderBuilder.create()
+                .add(target, new NTCredentials("test", "test".toCharArray(), null, null))
+                .build();
 
         this.httpclient = HttpClients.custom()
                 .setDefaultCredentialsProvider(credsProvider)
@@ -118,9 +118,9 @@ public class TestClientAuthenticationFakeNTLM extends LocalServerTestBase {
                 "AGUAcgB2AGUAcgA="));
         final HttpHost target = start();
 
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(new AuthScope(null, null, -1, null ,null),
-                new NTCredentials("test", "test".toCharArray(), null, null));
+        final CredentialsProvider credsProvider = CredentialsProviderBuilder.create()
+                .add(target, new NTCredentials("test", "test".toCharArray(), null, null))
+                .build();
 
         this.httpclient = HttpClients.custom()
                 .setDefaultCredentialsProvider(credsProvider)
@@ -142,9 +142,9 @@ public class TestClientAuthenticationFakeNTLM extends LocalServerTestBase {
                 "AGUAcgB2AGUAcgACAAwARABvAG0AYQBpAG4AAQAMAFMAZQByAHYAZQByAAAAAAA="));
         final HttpHost target = start();
 
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(new AuthScope(null, null, -1, null ,null),
-                new NTCredentials("test", "test".toCharArray(), null, null));
+        final CredentialsProvider credsProvider = CredentialsProviderBuilder.create()
+                .add(target, new NTCredentials("test", "test".toCharArray(), null, null))
+                .build();
 
         this.httpclient = HttpClients.custom()
                 .setDefaultCredentialsProvider(credsProvider)
@@ -187,10 +187,9 @@ public class TestClientAuthenticationFakeNTLM extends LocalServerTestBase {
         final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(new AuthScope(null, null, -1, null ,null),
-                new NTCredentials("test", "test".toCharArray(), null, null));
-        context.setCredentialsProvider(credsProvider);
+        context.setCredentialsProvider(CredentialsProviderBuilder.create()
+                .add(target, new NTCredentials("test", "test".toCharArray(), null, null))
+                .build());
         final HttpGet httpget = new HttpGet("/");
 
         final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context);
@@ -208,10 +207,9 @@ public class TestClientAuthenticationFakeNTLM extends LocalServerTestBase {
         final HttpHost target = start();
 
         final HttpClientContext context = HttpClientContext.create();
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(new AuthScope(null, null, -1, null ,null),
-                new NTCredentials("test", "test".toCharArray(), null, null));
-        context.setCredentialsProvider(credsProvider);
+        context.setCredentialsProvider(CredentialsProviderBuilder.create()
+                .add(target, new NTCredentials("test", "test".toCharArray(), null, null))
+                .build());
         final HttpGet httpget = new HttpGet("/");
 
         final ClassicHttpResponse response = this.httpclient.execute(target, httpget, context);
diff --git a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestSPNegoScheme.java b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestSPNegoScheme.java
index 6947d8f..1a516b1 100644
--- a/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestSPNegoScheme.java
+++ b/httpclient5-testing/src/test/java/org/apache/hc/client5/testing/sync/TestSPNegoScheme.java
@@ -34,10 +34,11 @@ import org.apache.hc.client5.http.auth.AuthScheme;
 import org.apache.hc.client5.http.auth.AuthSchemeFactory;
 import org.apache.hc.client5.http.auth.AuthScope;
 import org.apache.hc.client5.http.auth.Credentials;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
 import org.apache.hc.client5.http.auth.KerberosConfig;
 import org.apache.hc.client5.http.auth.StandardAuthScheme;
 import org.apache.hc.client5.http.classic.methods.HttpGet;
-import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
 import org.apache.hc.client5.http.impl.auth.SPNegoScheme;
 import org.apache.hc.client5.http.impl.classic.HttpClients;
 import org.apache.hc.core5.http.ClassicHttpRequest;
@@ -153,9 +154,9 @@ public class TestSPNegoScheme extends LocalServerTestBase {
         final HttpHost target = start();
 
         final AuthSchemeFactory nsf = new NegotiateSchemeFactoryWithMockGssManager();
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials use_jaas_creds = new UseJaasCredentials();
-        credentialsProvider.setCredentials(new AuthScope(null, null, -1, null, null), use_jaas_creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(null, null, -1, null, null), new UseJaasCredentials())
+                .build();
 
         final Registry<AuthSchemeFactory> authSchemeRegistry = RegistryBuilder.<AuthSchemeFactory>create()
             .register(StandardAuthScheme.SPNEGO, nsf)
@@ -184,9 +185,9 @@ public class TestSPNegoScheme extends LocalServerTestBase {
 
         final AuthSchemeFactory nsf = new NegotiateSchemeFactoryWithMockGssManager();
 
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials use_jaas_creds = new UseJaasCredentials();
-        credentialsProvider.setCredentials(new AuthScope(null, null, -1, null, null), use_jaas_creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(null, null, -1, null, null), new UseJaasCredentials())
+                .build();
 
         final Registry<AuthSchemeFactory> authSchemeRegistry = RegistryBuilder.<AuthSchemeFactory>create()
             .register(StandardAuthScheme.SPNEGO, nsf)
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicCredentialsProvider.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicCredentialsProvider.java
index 579d8b2..e58dc11 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicCredentialsProvider.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicCredentialsProvider.java
@@ -26,7 +26,6 @@
  */
 package org.apache.hc.client5.http.impl.auth;
 
-import java.util.Map;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.hc.client5.http.auth.AuthScope;
@@ -63,43 +62,9 @@ public class BasicCredentialsProvider implements CredentialsStore {
         credMap.put(authScope, credentials);
     }
 
-    /**
-     * Find matching {@link Credentials credentials} for the given authentication scope.
-     *
-     * @param map the credentials hash map
-     * @param authScope the {@link AuthScope authentication scope}
-     * @return the credentials
-     *
-     */
-    private static Credentials matchCredentials(
-            final Map<AuthScope, Credentials> map,
-            final AuthScope authScope) {
-        // see if we get a direct hit
-        Credentials creds = map.get(authScope);
-        if (creds == null) {
-            // Nope.
-            // Do a full scan
-            int bestMatchFactor  = -1;
-            AuthScope bestMatch  = null;
-            for (final AuthScope current: map.keySet()) {
-                final int factor = authScope.match(current);
-                if (factor > bestMatchFactor) {
-                    bestMatchFactor = factor;
-                    bestMatch = current;
-                }
-            }
-            if (bestMatch != null) {
-                creds = map.get(bestMatch);
-            }
-        }
-        return creds;
-    }
-
     @Override
-    public Credentials getCredentials(final AuthScope authScope,
-                                      final HttpContext httpContext) {
-        Args.notNull(authScope, "Authentication scope");
-        return matchCredentials(this.credMap, authScope);
+    public Credentials getCredentials(final AuthScope authScope, final HttpContext context) {
+        return CredentialsMatcher.matchCredentials(this.credMap, authScope);
     }
 
     @Override
@@ -109,7 +74,7 @@ public class BasicCredentialsProvider implements CredentialsStore {
 
     @Override
     public String toString() {
-        return credMap.toString();
+        return credMap.keySet().toString();
     }
 
 }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicCredentialsProvider.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/CredentialsMatcher.java
similarity index 59%
copy from httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicCredentialsProvider.java
copy to httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/CredentialsMatcher.java
index 579d8b2..ea334f3 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicCredentialsProvider.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/CredentialsMatcher.java
@@ -27,41 +27,11 @@
 package org.apache.hc.client5.http.impl.auth;
 
 import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
 
 import org.apache.hc.client5.http.auth.AuthScope;
 import org.apache.hc.client5.http.auth.Credentials;
-import org.apache.hc.client5.http.auth.CredentialsStore;
-import org.apache.hc.core5.annotation.Contract;
-import org.apache.hc.core5.annotation.ThreadingBehavior;
-import org.apache.hc.core5.http.protocol.HttpContext;
-import org.apache.hc.core5.util.Args;
 
-/**
- * Default implementation of {@link CredentialsStore}.
- *
- * @since 4.0
- */
-@Contract(threading = ThreadingBehavior.SAFE)
-public class BasicCredentialsProvider implements CredentialsStore {
-
-    private final ConcurrentHashMap<AuthScope, Credentials> credMap;
-
-    /**
-     * Default constructor.
-     */
-    public BasicCredentialsProvider() {
-        super();
-        this.credMap = new ConcurrentHashMap<>();
-    }
-
-    @Override
-    public void setCredentials(
-            final AuthScope authScope,
-            final Credentials credentials) {
-        Args.notNull(authScope, "Authentication scope");
-        credMap.put(authScope, credentials);
-    }
+final class CredentialsMatcher {
 
     /**
      * Find matching {@link Credentials credentials} for the given authentication scope.
@@ -71,9 +41,7 @@ public class BasicCredentialsProvider implements CredentialsStore {
      * @return the credentials
      *
      */
-    private static Credentials matchCredentials(
-            final Map<AuthScope, Credentials> map,
-            final AuthScope authScope) {
+    static Credentials matchCredentials(final Map<AuthScope, Credentials> map, final AuthScope authScope) {
         // see if we get a direct hit
         Credentials creds = map.get(authScope);
         if (creds == null) {
@@ -95,21 +63,4 @@ public class BasicCredentialsProvider implements CredentialsStore {
         return creds;
     }
 
-    @Override
-    public Credentials getCredentials(final AuthScope authScope,
-                                      final HttpContext httpContext) {
-        Args.notNull(authScope, "Authentication scope");
-        return matchCredentials(this.credMap, authScope);
-    }
-
-    @Override
-    public void clear() {
-        this.credMap.clear();
-    }
-
-    @Override
-    public String toString() {
-        return credMap.toString();
-    }
-
 }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/CredentialsProviderBuilder.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/CredentialsProviderBuilder.java
new file mode 100644
index 0000000..74fcc38
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/CredentialsProviderBuilder.java
@@ -0,0 +1,104 @@
+/*
+ * ====================================================================
+ * 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 java.util.HashMap;
+import java.util.Map;
+
+import org.apache.hc.client5.http.auth.AuthScope;
+import org.apache.hc.client5.http.auth.Credentials;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
+import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
+import org.apache.hc.core5.http.HttpHost;
+import org.apache.hc.core5.util.Args;
+
+/**
+ * {@link CredentialsProvider} builder.
+ *
+ * @since 5.2
+ */
+public final class CredentialsProviderBuilder {
+
+    private final Map<AuthScope, Credentials> credMap;
+
+    public static CredentialsProviderBuilder create() {
+        return new CredentialsProviderBuilder();
+    }
+
+    public CredentialsProviderBuilder() {
+        super();
+        this.credMap = new HashMap<>();
+    }
+
+    public CredentialsProviderBuilder add(final AuthScope authScope, final Credentials credentials) {
+        Args.notNull(authScope, "Host");
+        credMap.put(authScope, credentials);
+        return this;
+    }
+
+    public CredentialsProviderBuilder add(final AuthScope authScope, final String username, final char[] password) {
+        Args.notNull(authScope, "Host");
+        credMap.put(authScope, new UsernamePasswordCredentials(username, password));
+        return this;
+    }
+
+    public CredentialsProviderBuilder add(final HttpHost httpHost, final Credentials credentials) {
+        Args.notNull(httpHost, "Host");
+        credMap.put(new AuthScope(httpHost), credentials);
+        return this;
+    }
+
+    public CredentialsProviderBuilder add(final HttpHost httpHost, final String username, final char[] password) {
+        Args.notNull(httpHost, "Host");
+        credMap.put(new AuthScope(httpHost), new UsernamePasswordCredentials(username, password));
+        return this;
+    }
+
+    public CredentialsProvider build() {
+        if (credMap.size() == 0) {
+            return new BasicCredentialsProvider();
+        } else if (credMap.size() == 1) {
+            final Map.Entry<AuthScope, Credentials> entry = credMap.entrySet().iterator().next();
+            return new SingleCredentialsProvider(entry.getKey(), entry.getValue());
+        } else {
+            return new FixedCredentialsProvider(credMap);
+        }
+    }
+
+    static class Entry {
+
+        final AuthScope authScope;
+        final Credentials credentials;
+
+        Entry(final AuthScope authScope, final Credentials credentials) {
+            this.authScope = authScope;
+            this.credentials = credentials;
+        }
+
+    }
+
+}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/FixedCredentialsProvider.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/FixedCredentialsProvider.java
new file mode 100644
index 0000000..e42d141
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/FixedCredentialsProvider.java
@@ -0,0 +1,57 @@
+/*
+ * ====================================================================
+ * 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 java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.hc.client5.http.auth.AuthScope;
+import org.apache.hc.client5.http.auth.Credentials;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
+import org.apache.hc.core5.http.protocol.HttpContext;
+
+final class FixedCredentialsProvider implements CredentialsProvider {
+
+    private final Map<AuthScope, Credentials> credMap;
+
+    public FixedCredentialsProvider(final Map<AuthScope, Credentials> credMap) {
+        super();
+        this.credMap = Collections.unmodifiableMap(new HashMap<>(credMap));
+    }
+
+    @Override
+    public Credentials getCredentials(final AuthScope authScope, final HttpContext context) {
+        return CredentialsMatcher.matchCredentials(this.credMap, authScope);
+    }
+
+    @Override
+    public String toString() {
+        return credMap.keySet().toString();
+    }
+
+}
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SingleCredentialsProvider.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SingleCredentialsProvider.java
new file mode 100644
index 0000000..c17fd90
--- /dev/null
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/SingleCredentialsProvider.java
@@ -0,0 +1,61 @@
+/*
+ * ====================================================================
+ * 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.auth.AuthScope;
+import org.apache.hc.client5.http.auth.Credentials;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
+import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
+import org.apache.hc.core5.http.protocol.HttpContext;
+import org.apache.hc.core5.util.Args;
+
+final class SingleCredentialsProvider implements CredentialsProvider {
+
+    private final AuthScope authScope;
+    private final Credentials credentials;
+
+    public SingleCredentialsProvider(final AuthScope authScope, final Credentials credentials) {
+        super();
+        this.authScope = Args.notNull(authScope, "Auth scope");
+        this.credentials = credentials;
+    }
+
+    public SingleCredentialsProvider(final AuthScope authScope, final String username, final char[] password) {
+        this(authScope, new UsernamePasswordCredentials(username, password));
+    }
+
+    @Override
+    public Credentials getCredentials(final AuthScope authScope, final HttpContext context) {
+        return this.authScope.match(authScope) >= 0 ? credentials : null;
+    }
+
+    @Override
+    public String toString() {
+        return authScope.toString();
+    }
+
+}
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientAuthentication.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientAuthentication.java
index d917e2a..ec40910 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientAuthentication.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/AsyncClientAuthentication.java
@@ -33,12 +33,11 @@ import org.apache.hc.client5.http.async.methods.SimpleHttpResponse;
 import org.apache.hc.client5.http.async.methods.SimpleRequestBuilder;
 import org.apache.hc.client5.http.async.methods.SimpleRequestProducer;
 import org.apache.hc.client5.http.async.methods.SimpleResponseConsumer;
-import org.apache.hc.client5.http.auth.AuthScope;
-import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
 import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
 import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
-import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
 import org.apache.hc.core5.concurrent.FutureCallback;
+import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.message.StatusLine;
 import org.apache.hc.core5.io.CloseMode;
 
@@ -49,12 +48,10 @@ import org.apache.hc.core5.io.CloseMode;
 public class AsyncClientAuthentication {
 
     public static void main(final String[] args) throws Exception {
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(
-                new AuthScope("httpbin.org", 80),
-                new UsernamePasswordCredentials("user", "passwd".toCharArray()));
         final CloseableHttpAsyncClient httpclient = HttpAsyncClients.custom()
-                .setDefaultCredentialsProvider(credsProvider)
+                .setDefaultCredentialsProvider(CredentialsProviderBuilder.create()
+                        .add(new HttpHost("httpbin.org", 80), "user", "passwd".toCharArray())
+                        .build())
                 .build();
         httpclient.start();
 
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientAuthentication.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientAuthentication.java
index aa75fef..f8c681c 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientAuthentication.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientAuthentication.java
@@ -26,13 +26,12 @@
  */
 package org.apache.hc.client5.http.examples;
 
-import org.apache.hc.client5.http.auth.AuthScope;
-import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
 import org.apache.hc.client5.http.classic.methods.HttpGet;
-import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
 import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
 import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
 import org.apache.hc.client5.http.impl.classic.HttpClients;
+import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.io.entity.EntityUtils;
 
 /**
@@ -42,12 +41,10 @@ import org.apache.hc.core5.http.io.entity.EntityUtils;
 public class ClientAuthentication {
 
     public static void main(final String[] args) throws Exception {
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(
-                new AuthScope("httpbin.org", 80),
-                new UsernamePasswordCredentials("user", "passwd".toCharArray()));
         try (final CloseableHttpClient httpclient = HttpClients.custom()
-                .setDefaultCredentialsProvider(credsProvider)
+                .setDefaultCredentialsProvider(CredentialsProviderBuilder.create()
+                        .add(new HttpHost("httpbin.org", 80), "user", "passwd".toCharArray())
+                        .build())
                 .build()) {
             final HttpGet httpget = new HttpGet("http://httpbin.org/basic-auth/user/passwd");
 
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConfiguration.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConfiguration.java
index 92a494e..42d827e 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConfiguration.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientConfiguration.java
@@ -47,7 +47,7 @@ import org.apache.hc.client5.http.config.RequestConfig;
 import org.apache.hc.client5.http.cookie.BasicCookieStore;
 import org.apache.hc.client5.http.cookie.CookieStore;
 import org.apache.hc.client5.http.cookie.StandardCookieSpec;
-import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
 import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
 import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
 import org.apache.hc.client5.http.impl.classic.HttpClients;
@@ -194,7 +194,8 @@ public class ClientConfiguration {
         // Use custom cookie store if necessary.
         final CookieStore cookieStore = new BasicCookieStore();
         // Use custom credentials provider if necessary.
-        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .build();
         // Create global request configuration
         final RequestConfig defaultRequestConfig = RequestConfig.custom()
             .setCookieSpec(StandardCookieSpec.STRICT)
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientPreemptiveDigestAuthentication.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientPreemptiveDigestAuthentication.java
index 08af92d..0dbc463 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientPreemptiveDigestAuthentication.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientPreemptiveDigestAuthentication.java
@@ -28,10 +28,9 @@ package org.apache.hc.client5.http.examples;
 
 import org.apache.hc.client5.http.auth.AuthExchange;
 import org.apache.hc.client5.http.auth.AuthScheme;
-import org.apache.hc.client5.http.auth.AuthScope;
 import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
 import org.apache.hc.client5.http.classic.methods.HttpGet;
-import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
 import org.apache.hc.client5.http.impl.auth.DigestScheme;
 import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
 import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
@@ -54,11 +53,9 @@ public class ClientPreemptiveDigestAuthentication {
             final HttpHost target = new HttpHost("http", "httpbin.org", 80);
 
             final HttpClientContext localContext = HttpClientContext.create();
-            final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-            credentialsProvider.setCredentials(
-                    new AuthScope(target),
-                    new UsernamePasswordCredentials("user", "passwd".toCharArray()));
-            localContext.setCredentialsProvider(credentialsProvider);
+            localContext.setCredentialsProvider(CredentialsProviderBuilder.create()
+                    .add(target, new UsernamePasswordCredentials("user", "passwd".toCharArray()))
+                    .build());
 
             final HttpGet httpget = new HttpGet("http://httpbin.org/digest-auth/auth/user/passwd");
 
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientProxyAuthentication.java b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientProxyAuthentication.java
index 52bf5bf..d237029 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientProxyAuthentication.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/examples/ClientProxyAuthentication.java
@@ -27,10 +27,10 @@
 package org.apache.hc.client5.http.examples;
 
 import org.apache.hc.client5.http.auth.AuthScope;
-import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
 import org.apache.hc.client5.http.classic.methods.HttpGet;
 import org.apache.hc.client5.http.config.RequestConfig;
-import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
+import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
 import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
 import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
 import org.apache.hc.client5.http.impl.classic.HttpClients;
@@ -44,18 +44,16 @@ import org.apache.hc.core5.http.io.entity.EntityUtils;
 public class ClientProxyAuthentication {
 
     public static void main(final String[] args) throws Exception {
-        final BasicCredentialsProvider credsProvider = new BasicCredentialsProvider();
-        credsProvider.setCredentials(
-                new AuthScope("localhost", 8888),
-                new UsernamePasswordCredentials("squid", "squid".toCharArray()));
-        credsProvider.setCredentials(
-                new AuthScope("httpbin.org", 80),
-                new UsernamePasswordCredentials("user", "passwd".toCharArray()));
+        final CredentialsProvider credsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope("localhost", 8888), "squid", "squid".toCharArray())
+                .add(new AuthScope("httpbin.org", 80), "user", "passwd".toCharArray())
+                .build();
         final HttpHost target = new HttpHost("http", "httpbin.org", 80);
         final HttpHost proxy = new HttpHost("localhost", 8888);
         try (final CloseableHttpClient httpclient = HttpClients.custom()
                 .setProxy(proxy)
-                .setDefaultCredentialsProvider(credsProvider).build()) {
+                .setDefaultCredentialsProvider(credsProvider)
+                .build()) {
 
             final RequestConfig config = RequestConfig.custom()
                 .build();
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestAuthenticationStrategy.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestAuthenticationStrategy.java
index 3fff244..508fa14 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestAuthenticationStrategy.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/TestAuthenticationStrategy.java
@@ -38,11 +38,10 @@ import org.apache.hc.client5.http.auth.AuthSchemeFactory;
 import org.apache.hc.client5.http.auth.AuthScope;
 import org.apache.hc.client5.http.auth.ChallengeType;
 import org.apache.hc.client5.http.auth.StandardAuthScheme;
-import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
 import org.apache.hc.client5.http.config.RequestConfig;
-import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
 import org.apache.hc.client5.http.impl.auth.BasicScheme;
 import org.apache.hc.client5.http.impl.auth.BasicSchemeFactory;
+import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
 import org.apache.hc.client5.http.impl.auth.DigestScheme;
 import org.apache.hc.client5.http.impl.auth.DigestSchemeFactory;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
@@ -103,11 +102,9 @@ public class TestAuthenticationStrategy {
             .register(StandardAuthScheme.BASIC, BasicSchemeFactory.INSTANCE)
             .register(StandardAuthScheme.DIGEST, DigestSchemeFactory.INSTANCE).build();
         context.setAuthSchemeRegistry(authSchemeRegistry);
-
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        credentialsProvider.setCredentials(new AuthScope("somehost", 80),
-                new UsernamePasswordCredentials("user", "pwd".toCharArray()));
-        context.setCredentialsProvider(credentialsProvider);
+        context.setCredentialsProvider(CredentialsProviderBuilder.create()
+                .add(new AuthScope("somehost", 80), "user", "pwd".toCharArray())
+                .build());
 
         final List<AuthScheme> authSchemes = authStrategy.select(ChallengeType.TARGET, challenges, context);
         Assert.assertNotNull(authSchemes);
@@ -139,10 +136,9 @@ public class TestAuthenticationStrategy {
         context.setAuthSchemeRegistry(authSchemeRegistry);
         context.setRequestConfig(config);
 
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        credentialsProvider.setCredentials(new AuthScope("somehost", 80),
-                new UsernamePasswordCredentials("user", "pwd".toCharArray()));
-        context.setCredentialsProvider(credentialsProvider);
+        context.setCredentialsProvider(CredentialsProviderBuilder.create()
+                .add(new AuthScope("somehost", 80), "user", "pwd".toCharArray())
+                .build());
 
         final List<AuthScheme> authSchemes = authStrategy.select(ChallengeType.TARGET, challenges, context);
         Assert.assertNotNull(authSchemes);
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicScheme.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicScheme.java
index de2f4ce..675f0c8 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicScheme.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicScheme.java
@@ -39,6 +39,7 @@ import org.apache.hc.client5.http.auth.AuthScheme;
 import org.apache.hc.client5.http.auth.AuthScope;
 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.StandardAuthScheme;
 import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
 import org.apache.hc.core5.http.HttpHost;
@@ -81,10 +82,9 @@ public class TestBasicScheme {
         authscheme.processChallenge(authChallenge, null);
 
         final HttpHost host  = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "test", null);
-        final UsernamePasswordCredentials creds = new UsernamePasswordCredentials("testuser", "testpass".toCharArray());
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "test", null), "testuser", "testpass".toCharArray())
+                .build();
 
         final HttpRequest request = new BasicHttpRequest("GET", "/");
         Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
@@ -142,10 +142,9 @@ public class TestBasicScheme {
         authscheme.processChallenge(authChallenge, null);
 
         final HttpHost host  = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "test", null);
-        final UsernamePasswordCredentials creds = new UsernamePasswordCredentials("test", TEST_UTF8_PASSWORD.toCharArray());
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "test", null), "test", TEST_UTF8_PASSWORD.toCharArray())
+                .build();
 
         final HttpRequest request = new BasicHttpRequest("GET", "/");
         Assert.assertTrue(authscheme.isResponseReady(host, credentialsProvider, null));
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicCredentialsProvider.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestCredentialsProviders.java
similarity index 82%
rename from httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicCredentialsProvider.java
rename to httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestCredentialsProviders.java
index 1e4e3e3..b6c39a1 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestBasicCredentialsProvider.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestCredentialsProviders.java
@@ -26,18 +26,19 @@
  */
 package org.apache.hc.client5.http.impl.auth;
 
-import org.apache.hc.client5.http.auth.StandardAuthScheme;
 import org.apache.hc.client5.http.auth.AuthScope;
 import org.apache.hc.client5.http.auth.Credentials;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
+import org.apache.hc.client5.http.auth.StandardAuthScheme;
 import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
 import org.apache.hc.core5.http.HttpHost;
 import org.junit.Assert;
 import org.junit.Test;
 
 /**
- * Simple tests for {@link BasicCredentialsProvider}.
+ * Tests for {@link org.apache.hc.client5.http.auth.CredentialsProvider} implementations.
  */
-public class TestBasicCredentialsProvider {
+public class TestCredentialsProviders {
 
     public final static Credentials CREDS1 =
         new UsernamePasswordCredentials("user1", "pass1".toCharArray());
@@ -155,4 +156,21 @@ public class TestBasicCredentialsProvider {
         Assert.assertEquals(expected, got);
     }
 
+    @Test
+    public void testSingleCredentialsProvider() {
+        final Credentials creds1 = new UsernamePasswordCredentials("name1", "pass1".toCharArray());
+        final CredentialsProvider credentialsProvider1 = new SingleCredentialsProvider(new AuthScope(null, null, -1, null, null), creds1);
+
+        Assert.assertEquals(creds1, credentialsProvider1.getCredentials(new AuthScope(null, null, -1, null, null), null));
+        Assert.assertEquals(creds1, credentialsProvider1.getCredentials(new AuthScope("http", "someotherhost", 80, "somerealm", StandardAuthScheme.BASIC), null));
+
+        final CredentialsProvider credentialsProvider2 = new SingleCredentialsProvider(new AuthScope(null, "somehost", 80, null, null), creds1);
+
+        Assert.assertEquals(creds1, credentialsProvider2.getCredentials(new AuthScope(null, null, -1, null, null), null));
+        Assert.assertEquals(creds1, credentialsProvider2.getCredentials(new AuthScope(null, "somehost", 80, null, null), null));
+        Assert.assertEquals(creds1, credentialsProvider2.getCredentials(new AuthScope("http", "somehost", 80, "somerealm", StandardAuthScheme.BASIC), null));
+        Assert.assertNull(credentialsProvider2.getCredentials(new AuthScope(null, "someotherhost", 80, null, null), null));
+        Assert.assertNull(credentialsProvider2.getCredentials(new AuthScope(null, "somehost", 8080, null, null), null));
+    }
+
 }
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestDigestScheme.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestDigestScheme.java
index 7a5e430..31bfc63 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestDigestScheme.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestDigestScheme.java
@@ -42,10 +42,9 @@ import org.apache.hc.client5.http.auth.AuthScheme;
 import org.apache.hc.client5.http.auth.AuthScope;
 import org.apache.hc.client5.http.auth.AuthenticationException;
 import org.apache.hc.client5.http.auth.ChallengeType;
-import org.apache.hc.client5.http.auth.Credentials;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
 import org.apache.hc.client5.http.auth.MalformedChallengeException;
 import org.apache.hc.client5.http.auth.StandardAuthScheme;
-import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
 import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.ContentType;
 import org.apache.hc.core5.http.HeaderElement;
@@ -96,10 +95,9 @@ public class TestDigestScheme {
     public void testDigestAuthenticationWithDefaultCreds() throws Exception {
         final HttpRequest request = new BasicHttpRequest("Simple", "/");
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "realm1", null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
+                .build();
 
         final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
         final AuthChallenge authChallenge = parse(challenge);
@@ -123,10 +121,9 @@ public class TestDigestScheme {
     public void testDigestAuthentication() throws Exception {
         final HttpRequest request = new BasicHttpRequest("Simple", "/");
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "realm1", null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
+                .build();
 
         final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
         final AuthChallenge authChallenge = parse(challenge);
@@ -147,10 +144,9 @@ public class TestDigestScheme {
     @Test
     public void testDigestAuthenticationInvalidInput() throws Exception {
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "realm1", null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
+                .build();
 
         final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
         final AuthChallenge authChallenge = parse(challenge);
@@ -169,10 +165,9 @@ public class TestDigestScheme {
     public void testDigestAuthenticationWithSHA() throws Exception {
         final HttpRequest request = new BasicHttpRequest("Simple", "/");
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "realm1", null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
+                .build();
 
         final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", " +
                 "nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
@@ -196,10 +191,9 @@ public class TestDigestScheme {
     public void testDigestAuthenticationWithQueryStringInDigestURI() throws Exception {
         final HttpRequest request = new BasicHttpRequest("Simple", "/?param=value");
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "realm1", null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
+                .build();
 
         final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
         final AuthChallenge authChallenge = parse(challenge);
@@ -221,10 +215,9 @@ public class TestDigestScheme {
     public void testDigestAuthenticationNoRealm() throws Exception {
         final HttpRequest request = new BasicHttpRequest("Simple", "/");
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "realm1", null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
+                .build();
 
         final String challenge = StandardAuthScheme.DIGEST + " no-realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
         final AuthChallenge authChallenge = parse(challenge);
@@ -240,10 +233,9 @@ public class TestDigestScheme {
     public void testDigestAuthenticationNoNonce() throws Exception {
         final HttpRequest request = new BasicHttpRequest("Simple", "/");
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "realm1", null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
+                .build();
 
         final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", no-nonce=\"f2a3f18799759d4f1a1c068b92b573cb\"";
         final AuthChallenge authChallenge = parse(challenge);
@@ -269,10 +261,9 @@ public class TestDigestScheme {
 
         final HttpRequest request = new BasicHttpRequest("Simple", "/");
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, realm, null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials(username, password.toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, realm, null), username, password.toCharArray())
+                .build();
 
         final String challenge=StandardAuthScheme.DIGEST + " realm=\"" + realm + "\", "
             + "nonce=\"" + nonce + "\", "
@@ -320,10 +311,9 @@ public class TestDigestScheme {
 
         final HttpRequest request = new BasicHttpRequest("Simple", "/");
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, realm, null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials(username, password.toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, realm, null), username, password.toCharArray())
+                .build();
 
         final String challenge=StandardAuthScheme.DIGEST + " realm=\"" + realm + "\", "
             + "nonce=\"" + nonce + "\", "
@@ -365,10 +355,9 @@ public class TestDigestScheme {
 
         final HttpRequest request = new BasicHttpRequest("Simple", "/");
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, realm, null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials(username, password.toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, realm, null), username, password.toCharArray())
+                .build();
 
         final String challenge=StandardAuthScheme.DIGEST + " realm=\"" + realm + "\", "
             + "nonce=\"" + nonce + "\", "
@@ -401,10 +390,9 @@ public class TestDigestScheme {
 
         final HttpRequest request = new BasicHttpRequest("Simple", "/");
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, realm, null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials(username, password.toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, realm, null), username, password.toCharArray())
+                .build();
 
         final String challenge=StandardAuthScheme.DIGEST + " realm=\"" + realm + "\", "
             + "nonce=\"" + nonce + "\", "
@@ -452,10 +440,9 @@ public class TestDigestScheme {
     public void testDigestNouceCount() throws Exception {
         final HttpRequest request = new BasicHttpRequest("GET", "/");
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "realm1", null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
+                .build();
 
         final String challenge1 = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", qop=auth";
         final AuthChallenge authChallenge1 = parse(challenge1);
@@ -496,11 +483,10 @@ public class TestDigestScheme {
     @Test
     public void testDigestMD5SessA1AndCnonceConsistency() throws Exception {
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "subnet.domain.com", null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
         final HttpRequest request = new BasicHttpRequest("GET", "/");
-        final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "subnet.domain.com", null), "username", "password".toCharArray())
+                .build();
 
         final String challenge1 = StandardAuthScheme.DIGEST + " qop=\"auth\", algorithm=MD5-sess, nonce=\"1234567890abcdef\", " +
                 "charset=utf-8, realm=\"subnet.domain.com\"";
@@ -579,10 +565,9 @@ public class TestDigestScheme {
         final ClassicHttpRequest request = new BasicClassicHttpRequest("Post", "/");
         request.setEntity(new StringEntity("abc\u00e4\u00f6\u00fcabc", StandardCharsets.ISO_8859_1));
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "realm1", null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
+                .build();
 
         final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
                 "qop=\"auth,auth-int\"";
@@ -606,10 +591,9 @@ public class TestDigestScheme {
     public void testDigestAuthenticationQopAuthIntNullEntity() throws Exception {
         final HttpRequest request = new BasicHttpRequest("Post", "/");
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "realm1", null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
+                .build();
 
         final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
                 "qop=\"auth-int\"";
@@ -634,10 +618,9 @@ public class TestDigestScheme {
         final ClassicHttpRequest request = new BasicClassicHttpRequest("Post", "/");
         request.setEntity(new InputStreamEntity(new ByteArrayInputStream(new byte[] {'a'}), -1, ContentType.DEFAULT_TEXT));
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "realm1", null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
+                .build();
 
         final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
                 "qop=\"auth,auth-int\"";
@@ -661,10 +644,9 @@ public class TestDigestScheme {
     public void testParameterCaseSensitivity() throws Exception {
         final HttpRequest request = new BasicHttpRequest("GET", "/");
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "-", null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "-", null), "username", "password".toCharArray())
+                .build();
 
         final String challenge = StandardAuthScheme.DIGEST + " Realm=\"-\", " +
                 "nonce=\"YjYuNGYyYmJhMzUuY2I5ZDhlZDE5M2ZlZDM 1Mjk3NGJkNTIyYjgyNTcwMjQ=\", " +
@@ -683,10 +665,9 @@ public class TestDigestScheme {
         final ClassicHttpRequest request = new BasicClassicHttpRequest("Post", "/");
         request.setEntity(new InputStreamEntity(new ByteArrayInputStream(new byte[] {'a'}), -1, ContentType.DEFAULT_TEXT));
         final HttpHost host = new HttpHost("somehost", 80);
-        final AuthScope authScope = new AuthScope(host, "realm1", null);
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        final Credentials creds = new UsernamePasswordCredentials("username","password".toCharArray());
-        credentialsProvider.setCredentials(authScope, creds);
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
+                .build();
 
         final String challenge = StandardAuthScheme.DIGEST + " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\", " +
                 "qop=\"auth-int\"";
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestRequestAuthCache.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestRequestAuthCache.java
index 88eb72e..d6959c1 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestRequestAuthCache.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestRequestAuthCache.java
@@ -31,6 +31,7 @@ import org.apache.hc.client5.http.auth.AuthCache;
 import org.apache.hc.client5.http.auth.AuthExchange;
 import org.apache.hc.client5.http.auth.AuthScope;
 import org.apache.hc.client5.http.auth.Credentials;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
 import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.client5.http.protocol.RequestAuthCache;
@@ -52,14 +53,13 @@ public class TestRequestAuthCache {
     private AuthScope authscope2;
     private BasicScheme authscheme1;
     private BasicScheme authscheme2;
-    private BasicCredentialsProvider credProvider;
+    private CredentialsProvider credProvider;
 
     @Before
     public void setUp() {
         this.target = new HttpHost("localhost", 80);
         this.proxy = new HttpHost("localhost", 8080);
 
-        this.credProvider = new BasicCredentialsProvider();
         this.creds1 = new UsernamePasswordCredentials("user1", "secret1".toCharArray());
         this.creds2 = new UsernamePasswordCredentials("user2", "secret2".toCharArray());
         this.authscope1 = new AuthScope(this.target);
@@ -67,8 +67,10 @@ public class TestRequestAuthCache {
         this.authscheme1 = new BasicScheme();
         this.authscheme2 = new BasicScheme();
 
-        this.credProvider.setCredentials(this.authscope1, this.creds1);
-        this.credProvider.setCredentials(this.authscope2, this.creds2);
+        this.credProvider = CredentialsProviderBuilder.create()
+                .add(this.authscope1, this.creds1)
+                .add(this.authscope2, this.creds2)
+                .build();
     }
 
     @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 cae10cf..730fbd1 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
@@ -35,15 +35,15 @@ import org.apache.hc.client5.http.HttpRoute;
 import org.apache.hc.client5.http.RouteInfo;
 import org.apache.hc.client5.http.auth.AuthScope;
 import org.apache.hc.client5.http.auth.ChallengeType;
+import org.apache.hc.client5.http.auth.CredentialsProvider;
 import org.apache.hc.client5.http.auth.StandardAuthScheme;
-import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
 import org.apache.hc.client5.http.classic.ExecChain;
 import org.apache.hc.client5.http.classic.ExecRuntime;
 import org.apache.hc.client5.http.classic.methods.HttpGet;
 import org.apache.hc.client5.http.entity.EntityBuilder;
 import org.apache.hc.client5.http.impl.TunnelRefusedException;
-import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
 import org.apache.hc.client5.http.impl.auth.BasicScheme;
+import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.core5.http.ClassicHttpRequest;
 import org.apache.hc.core5.http.ClassicHttpResponse;
@@ -238,9 +238,9 @@ public class TestConnectExec {
                 .build());
         final ClassicHttpResponse response2 = new BasicClassicHttpResponse(200, "OK");
 
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        credentialsProvider.setCredentials(new AuthScope(proxy), new UsernamePasswordCredentials("user", "pass".toCharArray()));
-        context.setCredentialsProvider(credentialsProvider);
+        context.setCredentialsProvider(CredentialsProviderBuilder.create()
+                .add(new AuthScope(proxy), "user", "pass".toCharArray())
+                .build());
 
         final ConnectionState connectionState = new ConnectionState();
         Mockito.doAnswer(connectionState.connectAnswer()).when(execRuntime).connectEndpoint(Mockito.any());
@@ -279,8 +279,9 @@ public class TestConnectExec {
                 .build());
         final ClassicHttpResponse response2 = new BasicClassicHttpResponse(200, "OK");
 
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        credentialsProvider.setCredentials(new AuthScope(proxy), new UsernamePasswordCredentials("user", "pass".toCharArray()));
+        final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
+                .add(new AuthScope(proxy), "user", "pass".toCharArray())
+                .build();
         context.setCredentialsProvider(credentialsProvider);
 
         final ConnectionState connectionState = new ConnectionState();
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 9f0fb6f..3e687cd 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
@@ -41,7 +41,6 @@ import org.apache.hc.client5.http.auth.ChallengeType;
 import org.apache.hc.client5.http.auth.Credentials;
 import org.apache.hc.client5.http.auth.CredentialsProvider;
 import org.apache.hc.client5.http.auth.StandardAuthScheme;
-import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
 import org.apache.hc.client5.http.classic.ExecChain;
 import org.apache.hc.client5.http.classic.ExecRuntime;
 import org.apache.hc.client5.http.classic.methods.HttpGet;
@@ -49,6 +48,7 @@ import org.apache.hc.client5.http.classic.methods.HttpPost;
 import org.apache.hc.client5.http.entity.EntityBuilder;
 import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider;
 import org.apache.hc.client5.http.impl.auth.BasicScheme;
+import org.apache.hc.client5.http.impl.auth.CredentialsProviderBuilder;
 import org.apache.hc.client5.http.impl.auth.NTLMScheme;
 import org.apache.hc.client5.http.protocol.HttpClientContext;
 import org.apache.hc.core5.http.ClassicHttpRequest;
@@ -211,9 +211,9 @@ public class TestProtocolExec {
                 .setStream(inStream2)
                 .build());
 
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user", "pass".toCharArray()));
-        context.setCredentialsProvider(credentialsProvider);
+        context.setCredentialsProvider(CredentialsProviderBuilder.create()
+                .add(new AuthScope(target), "user", "pass".toCharArray())
+                .build());
 
         Mockito.when(chain.proceed(
                 Mockito.same(request),
@@ -257,9 +257,9 @@ public class TestProtocolExec {
         authExchange.select(new NTLMScheme());
         context.setAuthExchange(target, authExchange);
 
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user", "pass".toCharArray()));
-        context.setCredentialsProvider(credentialsProvider);
+        context.setCredentialsProvider(CredentialsProviderBuilder.create()
+                .add(new AuthScope(target), "user", "pass".toCharArray())
+                .build());
 
         Mockito.when(chain.proceed(
                 Mockito.same(request),
@@ -297,9 +297,9 @@ public class TestProtocolExec {
                 .setStream(inStream1)
                 .build());
 
-        final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
-        credentialsProvider.setCredentials(new AuthScope(target), new UsernamePasswordCredentials("user", "pass".toCharArray()));
-        context.setCredentialsProvider(credentialsProvider);
+        context.setCredentialsProvider(CredentialsProviderBuilder.create()
+                .add(new AuthScope(target), "user", "pass".toCharArray())
+                .build());
 
         Mockito.when(chain.proceed(
                 Mockito.same(request),