JDK-6687282 : URLConnection for HTTPS connection through Proxy w/ Digest Authentication gives 400 Bad Request
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 5.0u15,6u5
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris,solaris_10
  • CPU: sparc
  • Submitted: 2008-04-11
  • Updated: 2011-05-17
  • Resolved: 2011-05-17
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.
Other Other JDK 6 JDK 7
5.0u17-revFixed 5.0u18Fixed 6u11-revFixed 7 b27Fixed
Description
URLConnection fails with error 400 (Bad Request) for an HTTPS connection 
through a Proxy server, that is configured to request Digest Authentication.

1. Testcase
-----------
Please find attached the following testcase: proxy-bug.jar

% jar tvf proxy-bug.jar
     0 Wed Apr 09 14:25:58 MEST 2008 META-INF/
    44 Wed Apr 09 14:25:58 MEST 2008 META-INF/MANIFEST.MF
  3526 Tue Feb 05 13:32:14 MET 2008 org/jsantander/proxybug/ProxyBug.java
 19325 Tue Feb 05 14:19:10 MET 2008 org/jsantander/proxybug/StoreCertTrustManager.java
%

The tescase will need a Forward Proxy server with "Digest Authentication".
Customer used Apache 2.2.6.

The testcase needs to be called like follows:

java -classpath . -DPROXY_USER=<user> -DPROXY_PASSWORD=<password> \
                  -DPROXY_HOST=<proxy-address> -DPROXY_PORT=<proxy-port> \
                  org.jsantander.proxybug.ProxyBug <https-url>

where <user>, <password>, <proxy-address>, <proxy-port> and <https-url> are the parameters 
appropriate for the environment.


2. Behaviour
------------
The testcase does the following :

 1.- Create an HTTPS URL.
 2.- Obtain an URLConnection with url.openConnection() providing a Proxy
 3.- Setup the SSLSocketFactory.
 4.- Setup the default Authenticator.
 5.- Read result from connection

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
 1.- Send CONNECT HTTP Request to the Proxy
 2.- Receive a 407 Proxy Authentication Required
 3.- Send new CONNECT with authentication credentials.
 4.- Receive 200 OK. The tunnel is established.
 5.- Send GET through the HTTPS tunnel
 6.- Receive HTTPS Response
ACTUAL -
 1.- Send CONNECT HTTP Request to the Proxy
 2.- Receive a 407 Proxy Authentication Required
 3.- Send new CONNECT with authentication credentials.
 4.- Receive 400 Bad Request


Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.

C:\>"c:\Program Files\Java\jre1.6.0_05\bin\java" 
-cp . -DPROXY_USER=jsantander -DPROXY_PASSWORD=jsantander123 
-DPROXY_HOST=127.0.0.1 -DPROXY_PORT=8000 org.jsantander.proxybug.ProxyBug https://eas3nc1.ascc.lucent.com:8943/msb
09-abr-2008 14:56:07 org.jsantander.proxybug.StoreCertTrustManager <init>
INFO: StoreCertTrustManager is beginning!
09-abr-2008 14:56:07 org.jsantander.proxybug.StoreCertTrustManager <init>
INFO: Leaving StoreCertTrustManager!
java.io.IOException: Unable to tunnel through proxy. Proxy returns "HTTP/1.1 400 Bad Request"
        at sun.net.www.protocol.http.HttpURLConnection.doTunneling(Unknown Source)
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect (Unknown Source)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(Unknown Source)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(Unknown Source)
        at org.jsantander.proxybug.ProxyBug.main(ProxyBug.java:128)

C:\>
C:\>"c:\Program Files\Java\jre1.6.0_05\bin\java" -version
java version "1.6.0_05"
Java(TM) SE Runtime Environment (build 1.6.0_05-b13)
Java HotSpot(TM) Client VM (build 10.0-b19, mixed mode, sharing)
      

3. Symptoms
-----------
3.1 Apache log
--------------
 Apache's error log shows:
[Tue Feb 05 15:00:56 2008] [error] [client 135.92.88.74] Digest: uri mismatch
 - </wps/portal/ntchangepasswd> does not match request-uri <all.alcatel-lucent.com:443>


3.2 Etherreal trace
-------------------
Ethereal trace of the exchange

>> Frame 4 (220 bytes on wire, 220 bytes captured)
>> Ethernet II, Src: AlcatelN_8a:be:77 (00:d0:95:8a:be:77), Dst: Foxconn_7b:53:e1
>> (00:15:58:7b:53:e1)
>> Internet Protocol, Src: 135.92.88.74 (135.92.88.74), Dst: 159.23.107.247 (159.23.107.247)
>> Transmission Control Protocol, Src Port: 56859 (56859), Dst Port: 8000 (8000),
>> Seq: 1, Ack: 1, Len: 166
>> Hypertext Transfer Protocol
>>     CONNECT all.alcatel-lucent.com:443 HTTP/1.1\r\n
>>     User-Agent: Java/1.5.0_13\r\n
>>     Host: all.alcatel-lucent.com\r\n
>>     Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n
>>     \r\n
>>
>> Frame 5 (881 bytes on wire, 881 bytes captured)
>> Ethernet II, Src: Foxconn_7b:53:e1 (00:15:58:7b:53:e1), Dst: IETF-VRRP-virtual-router-VRID_cf
>> (00:00:5e:00:01:cf)
>> Internet Protocol, Src: 159.23.107.247 (159.23.107.247), Dst: 135.92.88.74 (135.92.88.74)
>> Transmission Control Protocol, Src Port: 8000 (8000), Dst Port: 56859 (56859),
>> Seq: 1, Ack: 167, Len: 827
>> Hypertext Transfer Protocol
>>     HTTP/1.1 407 Proxy Authentication Required\r\n
>>     Date: Tue, 05 Feb 2008 14:00:56 GMT\r\n
>>     Proxy-Authenticate: Digest realm="Restricted Files",
>>  nonce="K/Bnq2lFBAA=5da90dd82f45ce069133f035478844b5a08819c5", algorithm=MD5, qop="auth"\r\n
>>     Content-Length: 536
>>     Content-Type: text/html; charset=iso-8859-1\r\n
>>     \r\n
>> Line-based text data: text/html
>>
>> Frame 14 (531 bytes on wire, 531 bytes captured)
>> Ethernet II, Src: AlcatelN_8a:be:77 (00:d0:95:8a:be:77), Dst: Foxconn_7b:53:e1
>> (00:15:58:7b:53:e1)
>> Internet Protocol, Src: 135.92.88.74 (135.92.88.74), Dst: 159.23.107.247 (159.23.107.247)
>> Transmission Control Protocol, Src Port: 56860 (56860), Dst Port: 8000 (8000),
>> Seq: 1, Ack: 1, Len: 477
>> Hypertext Transfer Protocol
>>     CONNECT all.alcatel-lucent.com:443 HTTP/1.1\r\n
>>     User-Agent: Java/1.5.0_13\r\n
>>     Host: all.alcatel-lucent.com\r\n
>>     Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2\r\n
>>     Proxy-Authorization: Digest username="jsantander", realm="Restricted Files",
>>  nonce="K/Bnq2lFBAA=5da90dd82f45ce069133f035478844b5a08819c5", nc=00000001, 
>>  uri="/wps/portal/ntchangepasswd",
>>  response="5fb851590d4cdabd402613cd429815d2", algorith
>>     \r\n
>>
>> Frame 15 (551 bytes on wire, 551 bytes captured)
>> Ethernet II, Src: Foxconn_7b:53:e1 (00:15:58:7b:53:e1), Dst: IETF-VRRP-virtual-router-VRID_cf
>> (00:00:5e:00:01:cf)
>> Internet Protocol, Src: 159.23.107.247 (159.23.107.247), Dst: 135.92.88.74 (135.92.88.74)
>> Transmission Control Protocol, Src Port: 8000 (8000), Dst Port: 56860 (56860),
>> Seq: 1, Ack: 478, Len: 497
>> Hypertext Transfer Protocol
>>     HTTP/1.1 400 Bad Request\r\n
>>     Date: Tue, 05 Feb 2008 14:00:56 GMT\r\n
>>     Content-Length: 347
>>     Connection: close\r\n
>>     Content-Type: text/html; charset=iso-8859-1\r\n
>>     \r\n
>> Line-based text data: text/html
 

3.3 Apache's HttpClient
-----------------------
Problem can be cured by using Apache's HttpClient (http://hc.apache.org/httpclient-3.x/).
4. How to set up Apache2 as Forward Proxy Server w/ Digest Authentication
-------------------------------------------------------------------------

 I used Solaris 10 Apache2 2.0.52:

# /usr/apache2/bin/httpd -V
Server version: Apache/2.0.52
[ ... ]

 4.1  configure apache2
 ----------------------
# cd /etc/apache2
# cp httpd.conf-example httpd.conf

 make the following changes to httpd.conf

 4.1.1 change the following three lines
 --------------------------------------
 4.1.1.1
    Listen 80
 into
    Listen 8080

 4.1.1.2
     ServerAdmin ###@###.###
 into
     ServerAdmin <your_name>@sun.com

 4.1.1.3
     ServerName 127.0.0.1
 into
     ServerName <your_server_name>


 4.1.2  add the following lines after the "<IfModule mod_ssl.c>" block
 ---------------------------------------------------------------------
 add before line "### Section 3: Virtual Hosts"


  ProxyRequests On

<Proxy *>

  AuthType Digest
  AuthName "Private"
  AuthDigestFile /usr/local/apache/passwd/digest
  Require valid-user

</Proxy>


 4.2  configure Digest Authentication user
 -----------------------------------------
# mkdir -p /usr/local/apache/passwd
# /usr/apache2/bin/htdigest -c /usr/local/apache/passwd/digest Private dummy
Adding password for dummy in realm Private.
New password: dummypw
Re-type new password:
#

# more /usr/local/apache/passwd/digest
dummy:Private:f6bad2cc54d7f1b5667e78ab0a35e839
#

 4.3 Launch apache2 server
 -------------------------
# svcadm enable apache2

 Apache2 server should start up.
 Make sure apache server is running:
# ps -ef | grep apache
webservd  9849  9847   0 16:00:37 ?           0:00 /usr/apache2/bin/httpd -k start
    root  9847     1   0 16:00:36 ?           0:00 /usr/apache2/bin/httpd -k start
    root  9852  9847   0 16:00:37 ?           0:00 /usr/apache2/bin/httpd -k start
webservd  9850  9847   0 16:00:37 ?           0:00 /usr/apache2/bin/httpd -k start
webservd  9848  9847   0 16:00:37 ?           0:00 /usr/apache2/bin/httpd -k start
    root  9854  7283   0 16:00:37 pts/2       0:00 grep apache
webservd  9851  9847   0 16:00:37 ?           0:00 /usr/apache2/bin/httpd -k start
#


 4.4  Run client against apache proxy server
 -------------------------------------------
 possibly from a different host:

 /jdk1.6.0_04/bin/java -classpath . -DPROXY_USER=dummy -DPROXY_PASSWORD=dummypw \
 -DPROXY_HOST=<your_server_name>.<domain>.sun.com -DPROXY_PORT=8080 \
 org/jsantander/proxybug/ProxyBug https://www.sun.com/

 should give

Apr 17, 2008 3:46:41 PM org.jsantander.proxybug.StoreCertTrustManager <init>
INFO: StoreCertTrustManager is beginning!
Apr 17, 2008 3:46:41 PM org.jsantander.proxybug.StoreCertTrustManager <init>
INFO: Leaving StoreCertTrustManager!
java.io.IOException: Unable to tunnel through proxy. Proxy returns "HTTP/1.1 400 Bad Request"
        at sun.net.www.protocol.http.HttpURLConnection.doTunneling(HttpURLConnection.java:1423)
        at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:164)
        at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:977)
        at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:234)
        at org.jsantander.proxybug.ProxyBug.main(ProxyBug.java:128)
%

Comments
SUGGESTED FIX http://hg.openjdk.java.net/jdk7/jsn/jdk/rev/a954a6f3be6f
17-04-2008

EVALUATION Digest authentication uses the request-URI as part of its algorithm when generating the response hash. The request-URI is usually the abs_path of the uri, but not always. When tunneling the target servers 'host:port' is used as the request-URI, e.g. "CONNECT verisign.com:443 HTTP/1.1" The implementation in sun.net.www.protocol.http.DigestAuthentication only uses the abs_path of the uri. This is incorrect and the target servers 'host:port' should be used when tunneling. Also, the request method ( GET/POST/CONNECT ) is used when generating the response hash. This needs to be "CONNECT" when tunneling.
16-04-2008