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 2023/01/10 19:05:03 UTC

[httpcomponents-client] 01/06: Credentials interface should be able to represent different types of user credentials including token based with no password

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

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

commit e247276489e0e2b5732661d8bce6c30e299559b4
Author: Oleg Kalnichevski <ol...@apache.org>
AuthorDate: Sat Nov 26 18:28:36 2022 +0100

    Credentials interface should be able to represent different types of user credentials including token based with no password
---
 .../apache/hc/client5/http/auth/Credentials.java   |  5 ++++
 .../http/auth/UsernamePasswordCredentials.java     | 35 ++++++++++++++++++----
 .../hc/client5/http/impl/auth/BasicScheme.java     | 33 ++++++++------------
 .../hc/client5/http/impl/auth/DigestScheme.java    | 23 +++++++-------
 .../hc/client5/http/auth/TestCredentials.java      |  4 +--
 .../auth/TestSystemDefaultCredentialsProvider.java |  2 --
 6 files changed, 61 insertions(+), 41 deletions(-)

diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/auth/Credentials.java b/httpclient5/src/main/java/org/apache/hc/client5/http/auth/Credentials.java
index 742ba9e7b..491ee0072 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/auth/Credentials.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/auth/Credentials.java
@@ -39,6 +39,11 @@ public interface Credentials {
 
     Principal getUserPrincipal();
 
+    /**
+     * @deprecated Use specific credentials class that represent a username / password
+     * set of a security token.
+     */
+    @Deprecated
     char[] getPassword();
 
 }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/auth/UsernamePasswordCredentials.java b/httpclient5/src/main/java/org/apache/hc/client5/http/auth/UsernamePasswordCredentials.java
index 54fd469bc..f35f3fc5c 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/auth/UsernamePasswordCredentials.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/auth/UsernamePasswordCredentials.java
@@ -45,22 +45,36 @@ public class UsernamePasswordCredentials implements Credentials, Serializable {
 
     private static final long serialVersionUID = 243343858802739403L;
 
-    private final BasicUserPrincipal principal;
+    private final Principal principal;
     private final char[] password;
 
     /**
      * The constructor with the username and password arguments.
      *
-     * @param userName the user name
+     * @param principal the user principal
      * @param password the password
+     *
+     * @since 5.3
+     *
+     * @see BasicUserPrincipal
+     * @see NTUserPrincipal
      */
-    public UsernamePasswordCredentials(final String userName, final char[] password) {
+    public UsernamePasswordCredentials(final Principal principal, final char[] password) {
         super();
-        Args.notNull(userName, "Username");
-        this.principal = new BasicUserPrincipal(userName);
+        this.principal = Args.notNull(principal, "User principal");
         this.password = password;
     }
 
+    /**
+     * The constructor with the username and password arguments.
+     *
+     * @param username the user name
+     * @param password the password
+     */
+    public UsernamePasswordCredentials(final String username, final char[] password) {
+        this(new BasicUserPrincipal(username), password);
+    }
+
     @Override
     public Principal getUserPrincipal() {
         return this.principal;
@@ -70,6 +84,17 @@ public class UsernamePasswordCredentials implements Credentials, Serializable {
         return this.principal.getName();
     }
 
+    /**
+     * @since 5.3
+     */
+    public char[] getUserPassword() {
+        return password;
+    }
+
+    /**
+     * @deprecated Use {@link #getUserPassword()}.
+     */
+    @Deprecated
     @Override
     public char[] getPassword() {
         return password;
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java
index 87d11448c..d6d0d027c 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/BasicScheme.java
@@ -39,7 +39,6 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 
-import org.apache.hc.client5.http.utils.Base64;
 import org.apache.hc.client5.http.auth.AuthChallenge;
 import org.apache.hc.client5.http.auth.AuthScheme;
 import org.apache.hc.client5.http.auth.AuthScope;
@@ -49,7 +48,9 @@ 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.client5.http.protocol.HttpClientContext;
+import org.apache.hc.client5.http.utils.Base64;
 import org.apache.hc.client5.http.utils.ByteArrayBuilder;
 import org.apache.hc.core5.http.HttpHost;
 import org.apache.hc.core5.http.HttpRequest;
@@ -77,8 +78,7 @@ public class BasicScheme implements AuthScheme, Serializable {
     private transient Base64 base64codec;
     private boolean complete;
 
-    private String username;
-    private char[] password;
+    private UsernamePasswordCredentials credentials;
 
     /**
      * @since 4.3
@@ -93,21 +93,13 @@ public class BasicScheme implements AuthScheme, Serializable {
         this(StandardCharsets.US_ASCII);
     }
 
-    private void applyCredentials(final Credentials credentials) {
-        this.username = credentials.getUserPrincipal().getName();
-        this.password = credentials.getPassword();
-    }
-
-    private void clearCredentials() {
-        this.username = null;
-        this.password = null;
-    }
-
     public void initPreemptive(final Credentials credentials) {
         if (credentials != null) {
-            applyCredentials(credentials);
+            Args.check(credentials instanceof UsernamePasswordCredentials,
+                    "Unsupported credential type: " + credentials.getClass());
+            this.credentials = (UsernamePasswordCredentials) credentials;
         } else {
-            clearCredentials();
+            this.credentials = null;
         }
     }
 
@@ -157,8 +149,8 @@ public class BasicScheme implements AuthScheme, Serializable {
         final AuthScope authScope = new AuthScope(host, getRealm(), getName());
         final Credentials credentials = credentialsProvider.getCredentials(
                 authScope, context);
-        if (credentials != null) {
-            applyCredentials(credentials);
+        if (credentials instanceof UsernamePasswordCredentials) {
+            this.credentials = (UsernamePasswordCredentials) credentials;
             return true;
         }
 
@@ -167,7 +159,7 @@ public class BasicScheme implements AuthScheme, Serializable {
             final String exchangeId = clientContext.getExchangeId();
             LOG.debug("{} No credentials found for auth scope [{}]", exchangeId, authScope);
         }
-        clearCredentials();
+        this.credentials = null;
         return false;
     }
 
@@ -177,9 +169,10 @@ public class BasicScheme implements AuthScheme, Serializable {
     }
 
     private void validateUsername() throws AuthenticationException {
-        if (username == null) {
+        if (credentials == null) {
             throw new AuthenticationException("User credentials not set");
         }
+        final String username = credentials.getUserName();
         for (int i = 0; i < username.length(); i++) {
             final char ch = username.charAt(i);
             if (Character.isISOControl(ch)) {
@@ -204,7 +197,7 @@ public class BasicScheme implements AuthScheme, Serializable {
         }
         final Charset charset = AuthSchemeSupport.parseCharset(paramMap.get("charset"), defaultCharset);
         this.buffer.charset(charset);
-        this.buffer.append(this.username).append(":").append(this.password);
+        this.buffer.append(this.credentials.getUserName()).append(":").append(this.credentials.getUserPassword());
         if (this.base64codec == null) {
             this.base64codec = new Base64();
         }
diff --git a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestScheme.java b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestScheme.java
index ff98ab36a..f73f59055 100644
--- a/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestScheme.java
+++ b/httpclient5/src/main/java/org/apache/hc/client5/http/impl/auth/DigestScheme.java
@@ -53,6 +53,7 @@ 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.client5.http.protocol.HttpClientContext;
 import org.apache.hc.client5.http.utils.ByteArrayBuilder;
 import org.apache.hc.core5.annotation.Internal;
@@ -118,8 +119,7 @@ public class DigestScheme implements AuthScheme, Serializable {
     private byte[] a1;
     private byte[] a2;
 
-    private String username;
-    private char[] password;
+    private UsernamePasswordCredentials credentials;
 
     public DigestScheme() {
         this(StandardCharsets.ISO_8859_1);
@@ -133,8 +133,9 @@ public class DigestScheme implements AuthScheme, Serializable {
 
     public void initPreemptive(final Credentials credentials, final String cnonce, final String realm) {
         Args.notNull(credentials, "Credentials");
-        this.username = credentials.getUserPrincipal().getName();
-        this.password = credentials.getPassword();
+        Args.check(credentials instanceof UsernamePasswordCredentials,
+                "Unsupported credential type: " + credentials.getClass());
+        this.credentials = (UsernamePasswordCredentials) credentials;
         this.paramMap.put("cnonce", cnonce);
         this.paramMap.put("realm", realm);
     }
@@ -190,9 +191,8 @@ public class DigestScheme implements AuthScheme, Serializable {
         final AuthScope authScope = new AuthScope(host, getRealm(), getName());
         final Credentials credentials = credentialsProvider.getCredentials(
                 authScope, context);
-        if (credentials != null) {
-            this.username = credentials.getUserPrincipal().getName();
-            this.password = credentials.getPassword();
+        if (credentials instanceof UsernamePasswordCredentials) {
+            this.credentials = (UsernamePasswordCredentials) credentials;
             return true;
         }
 
@@ -201,8 +201,7 @@ public class DigestScheme implements AuthScheme, Serializable {
             final String exchangeId = clientContext.getExchangeId();
             LOG.debug("{} No credentials found for auth scope [{}]", exchangeId, authScope);
         }
-        this.username = null;
-        this.password = null;
+        this.credentials = null;
         return false;
     }
 
@@ -323,13 +322,13 @@ public class DigestScheme implements AuthScheme, Serializable {
             //      ":" unq(cnonce-value)
 
             // calculated one per session
-            buffer.append(username).append(":").append(realm).append(":").append(password);
+            buffer.append(credentials.getUserName()).append(":").append(realm).append(":").append(credentials.getUserPassword());
             final String checksum = formatHex(digester.digest(this.buffer.toByteArray()));
             buffer.reset();
             buffer.append(checksum).append(":").append(nonce).append(":").append(cnonce);
         } else {
             // unq(username-value) ":" unq(realm-value) ":" passwd
-            buffer.append(username).append(":").append(realm).append(":").append(password);
+            buffer.append(credentials.getUserName()).append(":").append(realm).append(":").append(credentials.getUserPassword());
         }
         a1 = buffer.toByteArray();
 
@@ -390,7 +389,7 @@ public class DigestScheme implements AuthScheme, Serializable {
         buffer.append(StandardAuthScheme.DIGEST + " ");
 
         final List<BasicNameValuePair> params = new ArrayList<>(20);
-        params.add(new BasicNameValuePair("username", username));
+        params.add(new BasicNameValuePair("username", credentials.getUserName()));
         params.add(new BasicNameValuePair("realm", realm));
         params.add(new BasicNameValuePair("nonce", nonce));
         params.add(new BasicNameValuePair("uri", uri));
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/auth/TestCredentials.java b/httpclient5/src/test/java/org/apache/hc/client5/http/auth/TestCredentials.java
index a3b1e7926..de14d7c48 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/auth/TestCredentials.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/auth/TestCredentials.java
@@ -44,14 +44,14 @@ public class TestCredentials {
         Assertions.assertEquals("name", creds1.getUserName());
         Assertions.assertEquals(new BasicUserPrincipal("name"),
                 creds1.getUserPrincipal());
-        Assertions.assertArrayEquals("pwd".toCharArray(), creds1.getPassword());
+        Assertions.assertArrayEquals("pwd".toCharArray(), creds1.getUserPassword());
         Assertions.assertEquals("[principal: name]", creds1.toString());
         final UsernamePasswordCredentials creds2 = new UsernamePasswordCredentials(
             "name", null);
         Assertions.assertEquals("name", creds2.getUserName());
         Assertions.assertEquals(new BasicUserPrincipal("name"),
                 creds2.getUserPrincipal());
-        Assertions.assertNull(creds2.getPassword());
+        Assertions.assertNull(creds2.getUserPassword());
         Assertions.assertEquals("[principal: name]", creds2.toString());
     }
 
diff --git a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestSystemDefaultCredentialsProvider.java b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestSystemDefaultCredentialsProvider.java
index 2c452a3f9..265b4c980 100644
--- a/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestSystemDefaultCredentialsProvider.java
+++ b/httpclient5/src/test/java/org/apache/hc/client5/http/impl/auth/TestSystemDefaultCredentialsProvider.java
@@ -104,7 +104,6 @@ public class TestSystemDefaultCredentialsProvider {
                                                                         RequestorType.SERVER);
         Assertions.assertNotNull(receivedCredentials);
         Assertions.assertEquals(AUTH1.getUserName(), receivedCredentials.getUserPrincipal().getName());
-        Assertions.assertEquals(AUTH1.getPassword(), receivedCredentials.getPassword());
     }
 
     @Test
@@ -122,7 +121,6 @@ public class TestSystemDefaultCredentialsProvider {
                                                                         RequestorType.SERVER);
         Assertions.assertNotNull(receivedCredentials);
         Assertions.assertEquals(AUTH1.getUserName(), receivedCredentials.getUserPrincipal().getName());
-        Assertions.assertEquals(AUTH1.getPassword(), receivedCredentials.getPassword());
     }
 
     private AuthenticatorDelegate installAuthenticator(final PasswordAuthentication returedAuthentication) {