Per RFC 7616, use the provided Response algorithm in the Request

For digest authentication, in RFC 7616 section "3.4 The Authorization
Header Field":

    The values of the opaque and algorithm fields must be those supplied
    in the WWW-Authenticate response header field for the entity being
    requested.

This commit honors that rule, and removes the previous behavior that
augmented the request header with "algorithm=MD5" when none was provided
in the server's response.

Aside from the specification, it also stands to reason that if the
server failed to provide "algorithm=..." in its "WWW-Authenticate"
header, the server should be fine with the client failing to provide
"algorithm=..." in the "Authorization" header.

The motivation for this change is that including "algorithm=MD5" in the
"Authorization" header causes http requests to fail when made to an
embedded system, which I suspect to be a an Espressif ESP32 web server.
This commit is contained in:
John Vasileff 2023-07-19 12:27:07 -04:00 committed by Oleg Kalnichevski
parent 9ad56ad734
commit d72a136817
2 changed files with 47 additions and 9 deletions

View File

@ -245,11 +245,7 @@ public class DigestScheme implements AuthScheme, Serializable {
final String realm = this.paramMap.get("realm");
final String nonce = this.paramMap.get("nonce");
final String opaque = this.paramMap.get("opaque");
String algorithm = this.paramMap.get("algorithm");
// If an algorithm is not specified, default to MD5.
if (algorithm == null) {
algorithm = "MD5";
}
final String algorithm = this.paramMap.get("algorithm");
final Set<String> qopset = new HashSet<>(8);
QualityOfProtection qop = QualityOfProtection.UNKNOWN;
@ -278,7 +274,8 @@ public class DigestScheme implements AuthScheme, Serializable {
final Charset charset = AuthSchemeSupport.parseCharset(paramMap.get("charset"), defaultCharset);
String digAlg = algorithm;
if (digAlg.equalsIgnoreCase("MD5-sess")) {
// If an algorithm is not specified, default to MD5.
if (digAlg == null || digAlg.equalsIgnoreCase("MD5-sess")) {
digAlg = "MD5";
}
@ -317,7 +314,7 @@ public class DigestScheme implements AuthScheme, Serializable {
a1 = null;
a2 = null;
// 3.2.2.2: Calculating digest
if (algorithm.equalsIgnoreCase("MD5-sess")) {
if ("MD5-sess".equalsIgnoreCase(algorithm)) {
// H( unq(username-value) ":" unq(realm-value) ":" passwd )
// ":" unq(nonce-value)
// ":" unq(cnonce-value)
@ -401,8 +398,9 @@ public class DigestScheme implements AuthScheme, Serializable {
params.add(new BasicNameValuePair("nc", nc));
params.add(new BasicNameValuePair("cnonce", cnonce));
}
// algorithm cannot be null here
params.add(new BasicNameValuePair("algorithm", algorithm));
if (algorithm != null) {
params.add(new BasicNameValuePair("algorithm", algorithm));
}
if (opaque != null) {
params.add(new BasicNameValuePair("opaque", opaque));
}

View File

@ -247,6 +247,46 @@ public class TestDigestScheme {
authscheme.generateAuthResponse(host, request, null));
}
@Test
public void testDigestAuthenticationNoAlgorithm() throws Exception {
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpHost host = new HttpHost("somehost", 80);
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);
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge, null);
final String authResponse = authscheme.generateAuthResponse(host, request, null);
final Map<String, String> table = parseAuthResponse(authResponse);
Assertions.assertNull(table.get("algorithm"));
}
@Test
public void testDigestAuthenticationMD5Algorithm() throws Exception {
final HttpRequest request = new BasicHttpRequest("Simple", "/");
final HttpHost host = new HttpHost("somehost", 80);
final CredentialsProvider credentialsProvider = CredentialsProviderBuilder.create()
.add(new AuthScope(host, "realm1", null), "username", "password".toCharArray())
.build();
final String challenge = StandardAuthScheme.DIGEST
+ " realm=\"realm1\", nonce=\"f2a3f18799759d4f1a1c068b92b573cb\""
+ ", algorithm=MD5";
final AuthChallenge authChallenge = parse(challenge);
final DigestScheme authscheme = new DigestScheme();
authscheme.processChallenge(authChallenge, null);
final String authResponse = authscheme.generateAuthResponse(host, request, null);
final Map<String, String> table = parseAuthResponse(authResponse);
Assertions.assertEquals("MD5", table.get("algorithm"));
}
/**
* Test digest authentication using the MD5-sess algorithm.
*/