JDK-8229962 : java.net.http.HttpClient authentication does not work with proxy tunnel
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.net
  • Affected Version: 11,13,14
  • Priority: P4
  • Status: Closed
  • Resolution: Not an Issue
  • OS: linux
  • CPU: x86_64
  • Submitted: 2019-08-14
  • Updated: 2021-02-16
  • Resolved: 2019-08-21
Related Reports
Relates :  
Description
A DESCRIPTION OF THE PROBLEM :
This bug only happens for a CONNECT proxy tunnel (e.g. https:// site via a proxy). The configured Authenticator is not called, no exception is thrown, and a "bare" HTTP 407 (with null response body) is returned to the user. 

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. start a fake proxy server that returns 407 on port 8000:
printf "HTTP/1.0 407 Unauthorized\r\nProxy-Authenticate: Basic\r\nContent-Type: text/plain\r\n\r\nthis is a body" | nc -l 8000

2. run the included java program
java repro.java

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The program should print "Authenticator called" and then throw IOException of "No credentials provided":
$ java repro.java
Authenticator called!
Exception in thread "main" java.io.IOException: No credentials provided
...

You can also see correct behavior if you change the test case URI from "https://example.org" to "http://example.org" because it will not use a CONNECT tunnel and behavior there is correct.
ACTUAL -
$java repro.java
HTTP_1_1 407 body=null


---------- BEGIN SOURCE ----------
import java.net.http.*;
import java.net.*;

public class repro {
  public static void main(String args[]) throws Exception {
    HttpClient.Builder builder = HttpClient.newBuilder();
    builder.authenticator(new Authenticator() {
      protected PasswordAuthentication getPasswordAuthentication() {
        System.out.println("Authenticator called!");
        return null;
      }
    });
    builder.proxy(ProxySelector.of(new InetSocketAddress("localhost", 8000)));
    HttpClient client = builder.build();
    HttpRequest request = HttpRequest.newBuilder(URI.create("https://example.org")).build();
    HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
    System.out.printf("%s %d body=%s\n", response.version(), response.statusCode(), response.body());
  }
}

---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Unfortunately there isn't an easy workaround I can find. I tried base64-encoding and setting "Proxy-Authorization: Basic xyz" header myself to bypass the authenticator api, but it doesn't get sent to the proxy.

FREQUENCY : always



Comments
From submitter: Thank you for explaining the issue, and sorry for the bogus report. I do want to suggest a javadocs hint for the user. Although the issue was documented in a JDK8 111 update release note, I started from scratch with JDK11 when building this app (specifically because it had java.net.http!): so I didn't think to look at the release notes for any old JDK8 updates. Thank you again!
22-08-2019

The java.net.HttpClient, like HttpURLConnection, also honors the jdk.http.auth.tunneling.disabledSchemes and jdk.http.auth.proxying.disabledSchemes networking properties. From the Release Notes for JDK 8 and JDK 8 Update Releases https://www.oracle.com/technetwork/java/javase/8all-relnotes-2226344.html "core-libs/java.net Disable Basic authentication for HTTPS tunneling In some environments, certain authentication schemes may be undesirable when proxying HTTPS. Accordingly, the Basic authentication scheme has been deactivated, by default, in the Oracle Java Runtime, by adding Basic to the jdk.http.auth.tunneling.disabledSchemes networking property. Now, proxies requiring Basic authentication when setting up a tunnel for HTTPS will no longer succeed by default. If required, this authentication scheme can be reactivated by removing Basic from the jdk.http.auth.tunneling.disabledSchemes networking property, or by setting a system property of the same name to "" ( empty ) on the command line. Additionally, the jdk.http.auth.tunneling.disabledSchemes and jdk.http.auth.proxying.disabledSchemes networking properties, and system properties of the same name, can be used to disable other authentication schemes that may be active when setting up a tunnel for HTTPS, or proxying plain HTTP, respectively." see also: JDK-8210814
21-08-2019

To reproduce the issue, follow the steps provided in the bug report. JDK 11.0.4 - Fail JDK 13-ea + 32 - Fail JDK 14-ea - Fail Output: HTTP_1_1 407 body=null
21-08-2019