はじめに
Java 8 Update 111 からjava.net
パッケージの HTTPS 接続の際のトンネリングに Basic 認証を使用できない設定がデフォルトになったようです。
回避するにはjdk.http.auth.tunneling.disabledSchemes
に空文字列を設定する必要があるそうです。
事象
背景
Java のjava.net.HttpURLConnection
を利用して、認証付きプロキシ内の環境から https のサイトにアクセスしようとした時に、どんな方法でプロキシの認証情報を付与しても407 Proxy Authentication Required
エラーを解消できなかった。
import java.util.*;
import java.net.*;
public class Sample {
private static String PROXY_HOST = "example.proxy.com";
private static String PROXY_PORT = "8080";
private static String PROXY_USER = "user";
private static String PROXY_PASSWORD = "password";
public static void main(String[] args) throws Exception {
String url = "https://news.google.com";
System.setProperty("proxySet", "true");
System.setProperty("proxyHost", PROXY_HOST);
System.setProperty("proxyPort", PROXY_PORT);
Authenticator.setDefault(new Authenticator() {
@Override
protected PasswordAuthentication getPasswordAuthentication() {
return new PasswordAuthentication(PROXY_USER, PROXY_PASSWORD.toCharArray());
}
});
HttpURLConnection urlconn = (HttpURLConnection) new URL(url).openConnection();
urlconn.setRequestMethod("GET");
urlconn.connect();
}
}
現象
上記の Java コードを実行すると下記のエラーが発生する。
$ java Sample
Exception in thread "main" java.io.IOException: Unable to tunnel through proxy. Proxy returns "HTTP/1.1 407 Proxy Authentication Required"
at sun.net.www.protocol.http.HttpURLConnection.doTunneling(HttpURLConnection.java:2124)
at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:183)
at sun.net.www.protocol.https.HttpsURLConnectionImpl.connect(HttpsURLConnectionImpl.java:153)
at Sample.main(Sample.java:25)
コード内での認証プロキシ設定だけでなく、下記も試しましたが結果はかわらず。
- Java 起動オプションに proxy の設定をする
- 例:
java -Dhttp.proxyHost="example.proxy.com" -Dhttp.proxyPort=8080 -Dhttp.proxyUser=user -Dhttp.proxyPassword=password (httpsに関しても同様に設定) Sample
- System デフォルトを参照するよう設定
- 例:
java -Djava.net.useSystemProxies=true Sample
環境
OS は Ubuntu 16.04、Java のバージョンは下記です。
$ java -version
java version "1.8.0_111"
Java(TM) SE Runtime Environment (build 1.8.0_111-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.111-b14, mixed mode)
結論
2016/10 にリリースされた 8u111 以降から、デフォルトの設定として HTTPS 接続する際のトンネリングに Basic 認証を利用することができなくなりました。
HTTPS トンネリングの Basic 認証の無効化 一部の環境で、HTTPS プロキシ時に特定の認証スキームが不適切である場合があります。そのため、Basic 認証スキームは、デフォルトでは Oracle Java Runtime で jdk.http.auth.tunneling.disabledSchemes ネットワーク・プロパティに Basic を追加することで非アクティブ化されています。HTTPS のトンネルの設定時に Basic 認証を必要とするプロキシは、デフォルトでは成功しないようになりました。必要な場合、jdk.http.auth.tunneling.disabledSchemes ネットワーク・プロパティから Basic を削除するか、コマンド行で同じ名前のシステム・プロパティを"" (空)に設定することで、この認証スキームを再度アクティブ化できます。また、jdk.http.auth.tunneling.disabledSchemes および jdk.http.auth.proxying.disabledSchemes ネットワーク・プロパティと同じ名前のシステム・プロパティは、それぞれ HTTPS のトンネルの設定時またはプレーンな HTTP のプロキシ時に、アクティブ化されている可能性があるその他の認証スキームを無効化するために使用できます。JDK-8160838 (非公開)
英語版のリリースノートを見ると、core-libs/java.net
と書いてあるので、java.net
パッケージ内のクラスの機能を使って HTTPS 接続する際のデフォルトの挙動の変更だと思われます。
回避方法
- JVM オプション
jdk.http.auth.tunneling.disabledSchemes=""
を設定する。
- 実行時:
java -Djdk.http.auth.tunneling.disabledSchemes="" Sample
- コード内:
System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
- 他のライブラリを使う
- Apache の HTTPClient など
補足
System.getProperty("jdk.http.auth.tunneling.disabledSchemes")
を sysout してみましたが、結果はnull
でした。