【Java】プロキシ設定のチェック機能を考える ~ その1 ~

■ はじめに

プロキシ設定のチェックを以下の関連記事であるようなコードで試してみた。
Javaping を考える
https://blogs.yahoo.co.jp/dk521123/37019179.html
しかし、以下の「問題点」が出た。

問題点

 Basic認証が設定してあるプロキシサーバで
Basic認証が認証が通った後に、認証NGになる設定をおこなった際に
前回のBasic認証が通っているのでエラーにならない

■ 原因

 * 以下のバグ表に載ってる問題で、2017/10/23現在でも解決できていない模様「Resolution: Unresolved」
JDK-6626700 : Request for ability to turn off authentication caching in HttpURLConnection
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6626700

解決策

sun の API を使うと解決できる
import sun.net.www.protocol.http.AuthCacheValue;
import sun.net.www.protocol.http.AuthCacheImpl;

・・・略・・・

AuthCacheValue.setAuthCache(new AuthCacheImpl());

■ サンプル

https://blogs.yahoo.co.jp/dk521123/36962466.html
でプロキシ環境を構築する。以下の環境下を想定する。

 * プロキシサーバ   :192.168.211.123
 * プロキシサーバポート:3128
 * 認証ID       :admin
 * 認証パスワード   :password

環境設定(Eclipse

* Eclipseの場合、エラーになるので、以下のように対処
 * プロジェクト名を右クリックし、
   [Properties]-[Java Compiler]-[Errors/Warnings]-[Deprecated and restricted API]で
  「Forbidden reference(access rules)」で「Error」⇒「Error」以外(「Warning」「Info」「Ignore」)にする

NetworkChecker.java

https://blogs.yahoo.co.jp/dk521123/37019179.html
をベースに作成する
import java.io.IOException;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.URL;

public class NetworkChecker {

  public static void main(String[] args) {
    System.out.println(
        "Result(OK) : " + ping("http://freerice.com/#/english-vocabulary/1528", 3000, "192.168.211.123", 3128, "admin", "password"));
    System.out.println(
        "Result(NG) : " + ping("http://freerice.com/#/english-vocabulary/1528", 3000, "192.168.211.123", 3128, "admin", "password1"));
  }

  public static boolean ping(String url, int timeout, String proxyHost, int proxyPort, String userName,
      String password) {
    if (userName != null && password != null) {
      // See https://qiita.com/kaakaa_hoe/items/d4fb11a3af035a287972
      System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");

      // ★ここに注目★
      NetworkChecker.clearAuthCache();
      
      Authenticator.setDefault(new Authenticator() {
        @Override
        protected PasswordAuthentication getPasswordAuthentication() {
          return new PasswordAuthentication(userName, password.toCharArray());
        }
      });
    }

    try {
      URL targetUrl = new URL(url);
      HttpURLConnection connection;
      if (proxyHost == null) {
        connection = (HttpURLConnection) targetUrl.openConnection();
      } else {
        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyHost, proxyPort));
        connection = (HttpURLConnection) targetUrl.openConnection(proxy);
      }
      connection.setConnectTimeout(timeout);
      connection.setReadTimeout(timeout);
      connection.setRequestMethod("HEAD");
      int responseCode = connection.getResponseCode();
      System.out.println("Response Code : " + responseCode);
      return (HttpURLConnection.HTTP_OK <= responseCode && responseCode <= 399);
    } catch (IOException exception) {
      return false;
    }
  }

  /**
   * 認証キャッシュのクリア(★ここに注目★).
   */
  @SuppressWarnings("restriction")
  private static void clearAuthCache() {
    sun.net.www.protocol.http.AuthCacheValue.setAuthCache(new sun.net.www.protocol.http.AuthCacheImpl());
  }
}

出力結果

Response Code : 200
Result(OK) : true
Response Code : 407
Result(NG) : false



関連記事

Java】プロキシ設定のチェック機能を考える ~ その2 ~

https://blogs.yahoo.co.jp/dk521123/37181766.html

Javaで、プロキシサーバ経由で接続する

https://blogs.yahoo.co.jp/dk521123/36966230.html

Linux】プロキシサーバソフト [2] ~ Squid / Basic認証編 ~

https://blogs.yahoo.co.jp/dk521123/36962466.html