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