JDK-8010505 : HTTP DIGEST implementation incorrectly quotes header values, fails auth
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 7u9
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2013-03-20
  • Updated: 2014-11-17
  • Resolved: 2013-04-19
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8 b89Fixed
Description
FULL PRODUCT VERSION :
java version  " 1.7.0_09 " 
OpenJDK Runtime Environment (IcedTea7 2.3.4) (7u9-2.3.4-0ubuntu1.12.10.1)
OpenJDK 64-Bit Server VM (build 23.2-b09, mixed mode)

ADDITIONAL OS VERSION INFORMATION :
Linux ygb1 3.5.0-22-generic #34-Ubuntu SMP Tue Jan 8 21:47:00 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux

A DESCRIPTION OF THE PROBLEM :
(For background see Tomcat issue #54060: https://issues.apache.org/bugzilla/show_bug.cgi?id=54060)

When connecting to a server that uses HTTP DIGEST authentication, the JDK implementation class sun.net.www.protocol.http.DigestAuthentication will create an Authorization header like so, and send it:

Digest username= " foo " , realm= " ****** " , nonce= " 1359097999996:13ed87b1b78c157232d609a099bcdb6e " , nc=00000001, uri= " /****** " , response= " b6f80b049b4b39000da79c96442e0740 " , algorithm= " MD5 " , opaque= " 3E8794E4CE80B19E5DF888D615FFBBA5 " , cnonce= " DGKKOPAFPJKCKKBDLFECINONACKFJIFNDOGKGLIO " , qop= " auth " 

The problem is that the values for qop= and algorithm= are quoted, when they should not be. See RFC 2617 (http://www.ietf.org/rfc/rfc2617.txt) section 3.2.2 and follow its references back to section 3.2.1.

While some servers ignore this, others don't. In particular, the most recent versions of Tomcat have begun rejecting the string. While they are implementing a workaround, it seems worth fixing.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Create a connection to a Tomcat 7.0.35 server that has enabled HTTP DIGEST authentication.

URL url = new URL( " http://example.org/ " )
HttpURLConnection connection = (HttpURLConnection) url.openConnection();

Authorization will fail even when the username and password are correct.


EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Successful authentication; an Authorization header like:

Digest username= " foo " , realm= " ****** " , nonce= " 1359097999996:13ed87b1b78c157232d609a099bcdb6e " , nc=00000001, uri= " /****** " , response= " b6f80b049b4b39000da79c96442e0740 " , algorithm=MD5, opaque= " 3E8794E4CE80B19E5DF888D615FFBBA5 " , cnonce= " DGKKOPAFPJKCKKBDLFECINONACKFJIFNDOGKGLIO " , qop=auth

(Note unquoted qop= and algorithm= values)
ACTUAL -
Failed authentication; an Authorization header like:

Digest username= " foo " , realm= " ****** " , nonce= " 1359097999996:13ed87b1b78c157232d609a099bcdb6e " , nc=00000001, uri= " /****** " , response= " b6f80b049b4b39000da79c96442e0740 " , algorithm= " MD5 " , opaque= " 3E8794E4CE80B19E5DF888D615FFBBA5 " , cnonce= " DGKKOPAFPJKCKKBDLFECINONACKFJIFNDOGKGLIO " , qop= " auth " 

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
URL url = new URL( " http://example.org/ " )
HttpURLConnection connection = (HttpURLConnection) url.openConnection();

(Where http://example.org/ must be replaced with a server running an HTTP implementation that will reject this header, like Tomcat 7.0.35)
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
I refer to a slightly outdated copy of the DigestAuthentication class:
http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7-b147/sun/net/www/protocol/http/DigestAuthentication.java?av=f#367

The fix is simple: do not surround the values of qop= and algorithm= with double quotes.
Comments
Release note added to the "Incompatibilities Between Java SE 8 and Java SE 7" section of the JDK 8 release notes.
17-02-2014

Suggested release note: --- In previous releases, the HttpURLConnection Digest Authentication implementation incorrectly quoted some values in the WWW-Authenticate Response Header. In the Java SE 8 release, these values are no longer quoted. This is in strict conformance with the RFC 2617, HTTP Authentication: Basic and Digest Access Authentication. Certain versions of some server implementations are known to expect the values to be quoted. HTTP requests to these servers may no longer successfully authenticate. While others, that previous may not have successfully authenticated because the values were quoted, may do so now. ---
13-02-2014

No, the "MD5" does not mean that the string should be quoted. In this context the quotation marks are part of the metasyntax. They mean that the literal string should appear, but not within actual quotes. Note that "algorithm" and "=" are also in quotes in this syntax specification, but neither of them should actually have quotes around them in the actual protocol stream. Where strings are to be quoted in the protocol stream, the metasyntactic variable quoted-string is used. For example, in the same section of the RFC, there is this: nonce = "nonce" "=" nonce-value nonce-value = quoted-string opaque = "opaque" "=" quoted-string Thus, the values for nonce and opaque should have quotes around them in the protocol stream, and indeed they do. In summary, in the protocol stream, MD5 and auth should not be surrounded by quotes.
11-02-2014

Section 3.2.1 from http://www.ietf.org/rfc/rfc2617.txt mentioned in bug description explicitly indicates that "MD5" value needs to quoted. Unquoting it seems results in authorization fails (JDK-8034170). algorithm = "algorithm" "=" ( "MD5" | "MD5-sess" | token ) qop-options = "qop" "=" <"> 1#qop-value <">
11-02-2014

I uploaded Connect.java... the test program that I used.
11-04-2013

I configured an Apache2 WWW server that uses DIGEST authentication, wrote a Java HTTP client that talks to the WWW server, instrumented: src/share/classes/sun/net/www/protocol/http/DigestAuthentication.java to print the authentication header, and then removed the extraneous quotation marks: jzavgren@ubuntuVM:~/code/java/HTTP/SimpleHTTPRequest$ java Connect user name/password: jzavgren/fast10k JRZ: Digest username="jzavgren", realm="private", nonce="KgAAAAAAAAA=674625d356df4153ea9e5b0a4ae379d4e571591a", nc=00000001, uri="/private", response="a0d38a6d4874e33877615f463a70984e", algorithm=MD5, cnonce="CANOGJHDLAMDHBCDNCMNJJBGMOJFFHKBLOAAMFJP", qop=auth JRZ: Digest username="jzavgren", realm="private", nonce="KgAAAAAAAAA=674625d356df4153ea9e5b0a4ae379d4e571591a", nc=00000002, uri="/private/", response="1e17da0bddbd24fdca07a0b386e4c0d5", algorithm=MD5, cnonce="HLKMAIFFEDGKDJPPAIJJPONAPAIMKHCBONIBKPAJ", qop=auth DATA: <html> <head> <title> Digest Authentication test page. </title> </head> <body> Digest-based authentication worked. </body> </html> I ran the test application (Connect.java) both before and after the modification and both versions worked against my Apache2 serv
11-04-2013