はじめに

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)

コード内での認証プロキシ設定だけでなく、下記も試しましたが結果はかわらず。

  1. Java 起動オプションに proxy の設定をする
  1. System デフォルトを参照するよう設定

環境

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 認証を利用することができなくなりました。

Java 8 リリースの変更

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 接続する際のデフォルトの挙動の変更だと思われます。

回避方法

  1. JVM オプションjdk.http.auth.tunneling.disabledSchemes=""を設定する。
  1. 他のライブラリを使う

補足

System.getProperty("jdk.http.auth.tunneling.disabledSchemes")を sysout してみましたが、結果はnullでした。

comments powered by Disqus