Enforce UTF-8 Encoding in BasicSchemeFactory for RFC 7617 Compliance (#506)

- Deprecated the constructor in BasicSchemeFactory that allows setting a custom Charset.
- Updated the default constructor to use StandardCharsets.UTF_8, aligning with RFC 7617 which mandates UTF-8 encoding for Basic Authentication.
This commit is contained in:
Arturo Bernal 2023-11-21 18:39:17 +01:00 committed by Oleg Kalnichevski
parent aa5bc56abe
commit 7b761fb2c3
7 changed files with 43 additions and 33 deletions

View File

@ -28,7 +28,6 @@ package org.apache.hc.client5.testing.async;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
@ -80,7 +79,7 @@ public class AuthenticatingAsyncDecorator implements AsyncServerExchangeHandler
}
public AuthenticatingAsyncDecorator(final AsyncServerExchangeHandler exchangeHandler, final Authenticator authenticator) {
this(exchangeHandler, new BasicAuthenticationHandler(StandardCharsets.US_ASCII), authenticator);
this(exchangeHandler, new BasicAuthenticationHandler(), authenticator);
}
protected void customizeUnauthorizedResponse(final HttpResponse unauthorized) {

View File

@ -32,25 +32,29 @@ import java.nio.charset.StandardCharsets;
import org.apache.hc.client5.http.auth.StandardAuthScheme;
import org.apache.hc.client5.http.utils.Base64;
import org.apache.hc.core5.util.Args;
public class BasicAuthenticationHandler extends AbstractAuthenticationHandler {
private final Charset charset;
/**
* @param charset the {@link Charset} set to be used for encoding credentials. This parameter is ignored as UTF-8 is always used.
* @since 5.3
* @deprecated This constructor is deprecated to enforce the use of {@link StandardCharsets#UTF_8} encoding
* in compliance with RFC 7617 for HTTP Basic Authentication. Use the default constructor {@link #BasicAuthenticationHandler()} instead.
*/
@Deprecated
public BasicAuthenticationHandler(final Charset charset) {
this.charset = Args.notNull(charset, "Charset");
this.charset = StandardCharsets.UTF_8; // Always use UTF-8
}
/**
* @deprecated Use {@link #BasicAuthenticationHandler(Charset)}
* Constructs a new BasicAuthenticationHandler with UTF-8 as the charset.
* This default setting aligns with standard practices for encoding credentials in Basic Authentication.
*
*/
@Deprecated
public BasicAuthenticationHandler() {
this(StandardCharsets.US_ASCII);
this.charset = StandardCharsets.UTF_8;
}
@Override

View File

@ -28,7 +28,6 @@
package org.apache.hc.client5.testing.classic;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
@ -71,7 +70,7 @@ public class AuthenticatingDecorator implements HttpServerRequestHandler {
public AuthenticatingDecorator(final HttpServerRequestHandler requestHandler,
final Authenticator authenticator) {
this(requestHandler, new BasicAuthenticationHandler(StandardCharsets.US_ASCII), authenticator);
this(requestHandler, new BasicAuthenticationHandler(), authenticator);
}
protected void customizeUnauthorizedResponse(final ClassicHttpResponse unauthorized) {

View File

@ -27,7 +27,6 @@
package org.apache.hc.client5.http;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
@ -111,7 +110,7 @@ public class ContextBuilder {
public ContextBuilder preemptiveBasicAuth(final HttpHost host, final UsernamePasswordCredentials credentials) {
Args.notNull(host, "HTTP host");
final BasicScheme authScheme = new BasicScheme(StandardCharsets.UTF_8);
final BasicScheme authScheme = new BasicScheme();
authScheme.initPreemptive(credentials);
preemptiveAuth(host, authScheme);
return this;

View File

@ -81,16 +81,27 @@ public class BasicScheme implements AuthScheme, Serializable {
private UsernamePasswordCredentials credentials;
/**
* @since 4.3
* @deprecated This constructor is deprecated to enforce the use of {@link StandardCharsets#UTF_8} encoding
* in compliance with RFC 7617 for HTTP Basic Authentication. Use the default constructor {@link #BasicScheme()} instead.
*
* @param charset the {@link Charset} set to be used for encoding credentials. This parameter is ignored as UTF-8 is always used.
*/
@Deprecated
public BasicScheme(final Charset charset) {
this.paramMap = new HashMap<>();
this.defaultCharset = charset != null ? charset : StandardCharsets.US_ASCII;
this.defaultCharset = StandardCharsets.UTF_8; // Always use UTF-8
this.complete = false;
}
/**
* Constructs a new BasicScheme with UTF-8 as the charset.
*
* @since 4.3
*/
public BasicScheme() {
this(StandardCharsets.US_ASCII);
this.paramMap = new HashMap<>();
this.defaultCharset = StandardCharsets.UTF_8;
this.complete = false;
}
public void initPreemptive(final Credentials credentials) {
@ -232,7 +243,7 @@ public class BasicScheme implements AuthScheme, Serializable {
try {
this.defaultCharset = Charset.forName(in.readUTF());
} catch (final UnsupportedCharsetException ex) {
this.defaultCharset = StandardCharsets.US_ASCII;
this.defaultCharset = StandardCharsets.UTF_8;
}
}

View File

@ -28,6 +28,7 @@
package org.apache.hc.client5.http.impl.auth;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import org.apache.hc.client5.http.auth.AuthScheme;
import org.apache.hc.client5.http.auth.AuthSchemeFactory;
@ -52,20 +53,28 @@ public class BasicSchemeFactory implements AuthSchemeFactory {
private final Charset charset;
/**
* @since 4.3
* @deprecated This constructor is deprecated to enforce the use of {@link StandardCharsets#UTF_8} encoding
* in compliance with RFC 7617 for HTTP Basic Authentication. Use the default constructor {@link #BasicSchemeFactory()} instead.
*
* @param charset the {@link Charset} set to be used for encoding credentials. This parameter is ignored as UTF-8 is always used.
*/
@Deprecated
public BasicSchemeFactory(final Charset charset) {
super();
this.charset = charset;
this.charset = StandardCharsets.UTF_8; // Always use UTF-8
}
/**
* Constructs a new {@link BasicSchemeFactory} with {@link StandardCharsets#UTF_8} as the charset.
* This default setting aligns with standard practices for encoding credentials in Basic Authentication.
*/
public BasicSchemeFactory() {
this(null);
this.charset = StandardCharsets.UTF_8;
}
@Override
public AuthScheme create(final HttpContext context) {
return new BasicScheme(this.charset);
return new BasicScheme();
}
}

View File

@ -104,25 +104,14 @@ public class TestBasicScheme {
static final String TEST_UTF8_PASSWORD = "123\u00A3";
@Test
public void testBasicAuthenticationDefaultCharsetASCII() throws Exception {
public void testBasicAuthenticationDefaultCharset() throws Exception {
final HttpHost host = new HttpHost("somehost", 80);
final UsernamePasswordCredentials creds = new UsernamePasswordCredentials("test", TEST_UTF8_PASSWORD.toCharArray());
final BasicScheme authscheme = new BasicScheme(StandardCharsets.US_ASCII);
final BasicScheme authscheme = new BasicScheme();
final HttpRequest request = new BasicHttpRequest("GET", "/");
authscheme.initPreemptive(creds);
final String authResponse = authscheme.generateAuthResponse(host, request, null);
Assertions.assertEquals("Basic dGVzdDoxMjM/", authResponse);
}
@Test
public void testBasicAuthenticationDefaultCharsetISO88591() throws Exception {
final HttpHost host = new HttpHost("somehost", 80);
final UsernamePasswordCredentials creds = new UsernamePasswordCredentials("test", TEST_UTF8_PASSWORD.toCharArray());
final BasicScheme authscheme = new BasicScheme(StandardCharsets.ISO_8859_1);
final HttpRequest request = new BasicHttpRequest("GET", "/");
authscheme.initPreemptive(creds);
final String authResponse = authscheme.generateAuthResponse(host, request, null);
Assertions.assertEquals("Basic dGVzdDoxMjOj", authResponse);
Assertions.assertEquals("Basic dGVzdDoxMjPCow==", authResponse);
}
@Test