ファイヤープロジェクト
HttpClientでの認証(HttpClient3.0-rc3)
2005-08-08T17:20+09:00   matsu
HttpClientでは,BASIC認証,DIGEST認証,NTLM認証が標準でサポートされているらしいので試してみた.
Httpサーバの認証にパスするためには,HttpClientにCredentialsオブジェクトを設定する. これは,HttpClient生成後に設定することもできるし,認証が必要になり次第処理動作をして設定することもできる. また,認証情報の送信タイミングとしてPreemptiveか否かを設定できる. Preemptiveを指定すると,サーバから要求される前に認証情報を送信することで,通信コストを下げることができる. また,認証情報を不正なサーバに送信することを防ぐために,スコープという概念もある. 本頁ではBASIC認証でこれらを一通り試すサンプルを作成した. このサンプルのメインのコードは以下である.
以下ではこれを元に記述する.
まず,認証のもっとも基本的な流れについて記述する. 認証をもっとも単純に行うためには,HttpClient生成後にCredentialオブジェクトを生成し,HttpClientオブジェクトに設定する.
// 認証情報(ユーザ名とパスワード)の作成.
Credentials defaultcreds1 = new UsernamePasswordCredentials("hoge", "hoge");
// 認証のスコープ.
AuthScope scope1 = new AuthScope("thor", 80, "HOGEUSER");
// スコープと認証情報の組合せをセット.
client.getState().setCredentials(scope1, defaultcreds1);

// 認証情報(ユーザ名とパスワード)の作成.
Credentials defaultcreds2 = new UsernamePasswordCredentials("fuga", "fuga");
// 認証のスコープ.
AuthScope scope2 = new AuthScope("thor", 80, "FUGAUSER");
// スコープと認証情報の組合せをセット.
client.getState().setCredentials(scope2, defaultcreds2);
Credentialsのサブクラスとして,UsernamePasswordCredentialsがある. このコンストラクタには,第一引数にユーザ名,第二引数にパスワードを指定する. また,作成したCredentialが有効なスコープを示すものとして,AuthScopeオブジェクトを生成する. これは,意図したサーバ以外に誤って認証情報を送信してしまわないために,存在する. スコープには,サーバ,ポート,レルムがある. 上記サンプルでは,二つの認証情報を,それぞれ別のレルムによるスコープとともに設定している. 最後にHttpMethodオブジェクトに認証処理を許可すると,スコープに応じて認証情報が送信されるようになる.
method.setDoAuthentication(authenticationFlag);
サンプルの実行結果を以下に示す(※).
$> java -jar httpclientsample.jar 1 http://thor/~matsu/hogedir/ http://thor/~matsu/fugadir/ http://thor/~matsu/fugadir/
2005-08-08 15:46:52,800 DEBUG [main] header Wire 69 - >> "GET /~matsu/hogedir/ HTTP/1.1[\r][\n]"
2005-08-08 15:46:52,837 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 15:46:52,840 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 15:46:52,841 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 15:46:52,852 DEBUG [main] header Wire 69 - << "HTTP/1.1 401 Authorization Required[\r][\n]"
2005-08-08 15:46:52,856 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 06:46:52 GMT[\r][\n]"
2005-08-08 15:46:52,857 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 15:46:52,858 DEBUG [main] header Wire 69 - << "WWW-Authenticate: Basic realm="HOGEUSER"[\r][\n]"
2005-08-08 15:46:52,859 DEBUG [main] header Wire 69 - << "Transfer-Encoding: chunked[\r][\n]"
2005-08-08 15:46:52,859 DEBUG [main] header Wire 69 - << "Content-Type: text/html; charset=iso-8859-1[\r][\n]"
2005-08-08 15:46:52,919 DEBUG [main] header Wire 69 - >> "GET /~matsu/hogedir/ HTTP/1.1[\r][\n]"
2005-08-08 15:46:52,921 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 15:46:52,922 DEBUG [main] header Wire 69 - >> "Authorization: Basic aG9nZTpob2dl[\r][\n]"
2005-08-08 15:46:52,923 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 15:46:52,923 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 15:46:52,928 DEBUG [main] header Wire 69 - << "HTTP/1.1 200 OK[\r][\n]"
2005-08-08 15:46:52,930 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 06:46:52 GMT[\r][\n]"
2005-08-08 15:46:52,930 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 15:46:52,931 DEBUG [main] header Wire 69 - << "Last-Modified: Sun, 07 Aug 2005 17:09:23 GMT[\r][\n]"
2005-08-08 15:46:52,932 DEBUG [main] header Wire 69 - << "ETag: "19f448-29-42f64043"[\r][\n]"
2005-08-08 15:46:52,934 DEBUG [main] header Wire 69 - << "Accept-Ranges: bytes[\r][\n]"
2005-08-08 15:46:52,935 DEBUG [main] header Wire 69 - << "Content-Length: 41[\r][\n]"
2005-08-08 15:46:52,937 DEBUG [main] header Wire 69 - << "Content-Type: text/html[\r][\n]"
<html>
<body>
PAGE HOGE
</body>
</html>


2005-08-08 15:46:52,945 DEBUG [main] header Wire 69 - >> "GET /~matsu/fugadir/ HTTP/1.1[\r][\n]"
2005-08-08 15:46:52,947 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 15:46:52,950 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 15:46:52,952 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 15:46:52,956 DEBUG [main] header Wire 69 - << "HTTP/1.1 401 Authorization Required[\r][\n]"
2005-08-08 15:46:52,957 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 06:46:52 GMT[\r][\n]"
2005-08-08 15:46:52,960 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 15:46:52,960 DEBUG [main] header Wire 69 - << "WWW-Authenticate: Basic realm="FUGAUSER"[\r][\n]"
2005-08-08 15:46:52,961 DEBUG [main] header Wire 69 - << "Transfer-Encoding: chunked[\r][\n]"
2005-08-08 15:46:52,961 DEBUG [main] header Wire 69 - << "Content-Type: text/html; charset=iso-8859-1[\r][\n]"
2005-08-08 15:46:52,965 DEBUG [main] header Wire 69 - >> "GET /~matsu/fugadir/ HTTP/1.1[\r][\n]"
2005-08-08 15:46:52,967 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 15:46:52,968 DEBUG [main] header Wire 69 - >> "Authorization: Basic ZnVnYTpmdWdh[\r][\n]"
2005-08-08 15:46:52,971 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 15:46:52,972 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 15:46:52,977 DEBUG [main] header Wire 69 - << "HTTP/1.1 200 OK[\r][\n]"
2005-08-08 15:46:52,978 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 06:46:52 GMT[\r][\n]"
2005-08-08 15:46:52,979 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 15:46:52,979 DEBUG [main] header Wire 69 - << "Last-Modified: Sun, 07 Aug 2005 17:09:23 GMT[\r][\n]"
2005-08-08 15:46:52,981 DEBUG [main] header Wire 69 - << "ETag: "19f443-29-42f64043"[\r][\n]"
2005-08-08 15:46:52,984 DEBUG [main] header Wire 69 - << "Accept-Ranges: bytes[\r][\n]"
2005-08-08 15:46:52,985 DEBUG [main] header Wire 69 - << "Content-Length: 41[\r][\n]"
2005-08-08 15:46:52,985 DEBUG [main] header Wire 69 - << "Content-Type: text/html[\r][\n]"
<html>
<body>
PAGE HOGE
</body>
</html>


2005-08-08 15:46:52,989 DEBUG [main] header Wire 69 - >> "GET /~matsu/fugadir/ HTTP/1.1[\r][\n]"
2005-08-08 15:46:52,990 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 15:46:52,991 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 15:46:52,993 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 15:46:52,995 DEBUG [main] header Wire 69 - << "HTTP/1.1 401 Authorization Required[\r][\n]"
2005-08-08 15:46:52,996 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 06:46:52 GMT[\r][\n]"
2005-08-08 15:46:52,997 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 15:46:52,998 DEBUG [main] header Wire 69 - << "WWW-Authenticate: Basic realm="FUGAUSER"[\r][\n]"
2005-08-08 15:46:52,999 DEBUG [main] header Wire 69 - << "Transfer-Encoding: chunked[\r][\n]"
2005-08-08 15:46:52,999 DEBUG [main] header Wire 69 - << "Content-Type: text/html; charset=iso-8859-1[\r][\n]"
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>401 Authorization Required</TITLE>
</HEAD><BODY>
<H1>Authorization Required</H1>
This server could not verify that you
are authorized to access the document
requested.  Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.<P>
<HR>
<ADDRESS>Apache/1.3.33 Server at thor Port 80</ADDRESS>
</BODY></HTML>
上記の実行では三回GETメソッドを発行しており,一回目はレルムHOGEUSER,二回目はレルムFUGAUSERの認証情報を要求されている. 三回目は,以下で認証情報の送信を拒否設定した場合の動作で,認証エラーがサーバから返されている.
method.setDoAuthentication(false);
※ 本頁と同様のサンプル実行結果を得るには,サーバ側環境を構築する必要がある. 話しがそれるので,詳細は記述しないが,ざっくり以下のような作業が必要である. まず,hogedirの.htaccessを以下とする.
AuthUserFile /home/user/ht_users
AuthGroupFile /dev/null         
AuthName "HOGEUSER"
AuthType Basic  

Require user hoge
そしてfugadierの.htaccessを以下とする.
AuthUserFile /home/user/ht_users
AuthGroupFile /dev/null         
AuthName "FUGAUSER"
AuthType Basic  

Require user fuga
あとはユーザhoge,fugaでhtpasswdし,各ディレクトリにコンテンツを置く. これらの設定は私の環境のものであり,各自のサーバでの環境によって具体的な設定値(パスワードファイルのパスなど)を読みかえる必要がある.
前節の設定では,サーバに一度GET要求し,サーバから認証情報を要求されてから,指定されたレルムの認証情報を送信していた.
// 一度GETを発行
2005-08-08 15:46:52,800 DEBUG [main] header Wire 69 - >> "GET /~matsu/hogedir/ HTTP/1.1[\r][\n]"
2005-08-08 15:46:52,837 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 15:46:52,840 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 15:46:52,841 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 15:46:52,852 DEBUG [main] header Wire 69 - << "HTTP/1.1 401 Authorization Required[\r][\n]"
2005-08-08 15:46:52,856 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 06:46:52 GMT[\r][\n]"
2005-08-08 15:46:52,857 DEBUG [main] header Wire 69
 - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"

// レルムHOGEUSERのBasic認証情報を要求される.
2005-08-08 15:46:52,858 DEBUG [main] header Wire 69 - << "WWW-Authenticate: Basic realm="HOGEUSER"[\r][\n]"
2005-08-08 15:46:52,859 DEBUG [main] header Wire 69 - << "Transfer-Encoding: chunked[\r][\n]"
2005-08-08 15:46:52,859 DEBUG [main] header Wire 69 - << "Content-Type: text/html; charset=iso-8859-1[\r][\n]"
2005-08-08 15:46:52,919 DEBUG [main] header Wire 69 - >> "GET /~matsu/hogedir/ HTTP/1.1[\r][\n]"
2005-08-08 15:46:52,921 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"

// レルムHOGEUSERのBasic認証情報を送信.
2005-08-08 15:46:52,922 DEBUG [main] header Wire 69 - >> "Authorization: Basic aG9nZTpob2dl[\r][\n]"
2005-08-08 15:46:52,923 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 15:46:52,923 DEBUG [main] header Wire 69 - >> "[\r][\n]"
この動作をnon-preemptiveモードという. preemptiveモードでは逆に,サーバから要求される以前に該当のスコープの認証情報を送信してしまう動作である. ただし,サーバに最初に要求する段階では,レルムが分からないので,同じサーバ,ポートのスコープに紐づく認証の中から,最初のものを送信する. preemptiveモードはHttpClientに対して設定する.
client.getParams().setAuthenticationPreemptive(authMode == AUTH_MODE_PREEMPTIVE);
authModeは,本頁のサンプルでの引数で,いろいろな動作を切替えるのに使用している. preemptiveモードでの動作結果を以下に示す.
$> java -jar httpclientsample.jar 0 http://thor/~matsu/hogedir/ http://thor/~matsu/fugadir/ http://thor/~matsu/fugadir/
2005-08-08 15:55:58,598 DEBUG [main] header Wire 69 - >> "GET /~matsu/hogedir/ HTTP/1.1[\r][\n]"
2005-08-08 15:55:58,646 DEBUG [main] header Wire 69 - >> "Authorization: Basic aG9nZTpob2dl[\r][\n]"
2005-08-08 15:55:58,651 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 15:55:58,652 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 15:55:58,653 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 15:55:58,657 DEBUG [main] header Wire 69 - << "HTTP/1.1 200 OK[\r][\n]"
2005-08-08 15:55:58,665 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 06:55:58 GMT[\r][\n]"
2005-08-08 15:55:58,666 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 15:55:58,666 DEBUG [main] header Wire 69 - << "Last-Modified: Sun, 07 Aug 2005 17:09:23 GMT[\r][\n]"
2005-08-08 15:55:58,667 DEBUG [main] header Wire 69 - << "ETag: "19f448-29-42f64043"[\r][\n]"
2005-08-08 15:55:58,668 DEBUG [main] header Wire 69 - << "Accept-Ranges: bytes[\r][\n]"
2005-08-08 15:55:58,671 DEBUG [main] header Wire 69 - << "Content-Length: 41[\r][\n]"
2005-08-08 15:55:58,672 DEBUG [main] header Wire 69 - << "Content-Type: text/html[\r][\n]"
<html>
<body>
PAGE HOGE
</body>
</html>


2005-08-08 15:55:58,696 DEBUG [main] header Wire 69 - >> "GET /~matsu/fugadir/ HTTP/1.1[\r][\n]"
2005-08-08 15:55:58,698 DEBUG [main] header Wire 69 - >> "Authorization: Basic aG9nZTpob2dl[\r][\n]"
2005-08-08 15:55:58,699 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 15:55:58,700 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 15:55:58,700 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 15:55:58,703 DEBUG [main] header Wire 69 - << "HTTP/1.1 401 Authorization Required[\r][\n]"
2005-08-08 15:55:58,705 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 06:55:58 GMT[\r][\n]"
2005-08-08 15:55:58,707 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 15:55:58,708 DEBUG [main] header Wire 69 - << "WWW-Authenticate: Basic realm="FUGAUSER"[\r][\n]"
2005-08-08 15:55:58,709 DEBUG [main] header Wire 69 - << "Transfer-Encoding: chunked[\r][\n]"
2005-08-08 15:55:58,712 DEBUG [main] header Wire 69 - << "Content-Type: text/html; charset=iso-8859-1[\r][\n]"
2005-08-08 15:55:58,722 DEBUG [main] header Wire 69 - >> "GET /~matsu/fugadir/ HTTP/1.1[\r][\n]"
2005-08-08 15:55:58,724 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 15:55:58,728 DEBUG [main] header Wire 69 - >> "Authorization: Basic ZnVnYTpmdWdh[\r][\n]"
2005-08-08 15:55:58,730 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 15:55:58,731 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 15:55:58,737 DEBUG [main] header Wire 69 - << "HTTP/1.1 200 OK[\r][\n]"
2005-08-08 15:55:58,740 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 06:55:58 GMT[\r][\n]"
2005-08-08 15:55:58,741 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 15:55:58,742 DEBUG [main] header Wire 69 - << "Last-Modified: Sun, 07 Aug 2005 17:09:23 GMT[\r][\n]"
2005-08-08 15:55:58,742 DEBUG [main] header Wire 69 - << "ETag: "19f443-29-42f64043"[\r][\n]"
2005-08-08 15:55:58,743 DEBUG [main] header Wire 69 - << "Accept-Ranges: bytes[\r][\n]"
2005-08-08 15:55:58,744 DEBUG [main] header Wire 69 - << "Content-Length: 41[\r][\n]"
2005-08-08 15:55:58,746 DEBUG [main] header Wire 69 - << "Content-Type: text/html[\r][\n]"
<html>
<body>
PAGE HOGE
</body>
</html>


2005-08-08 15:55:58,751 DEBUG [main] header Wire 69 - >> "GET /~matsu/fugadir/ HTTP/1.1[\r][\n]"
2005-08-08 15:55:58,752 DEBUG [main] header Wire 69 - >> "Authorization: Basic aG9nZTpob2dl[\r][\n]"
2005-08-08 15:55:58,753 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 15:55:58,754 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 15:55:58,754 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 15:55:58,758 DEBUG [main] header Wire 69 - << "HTTP/1.1 401 Authorization Required[\r][\n]"
2005-08-08 15:55:58,759 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 06:55:58 GMT[\r][\n]"
2005-08-08 15:55:58,761 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 15:55:58,764 DEBUG [main] header Wire 69 - << "WWW-Authenticate: Basic realm="FUGAUSER"[\r][\n]"
2005-08-08 15:55:58,765 DEBUG [main] header Wire 69 - << "Transfer-Encoding: chunked[\r][\n]"
2005-08-08 15:55:58,766 DEBUG [main] header Wire 69 - << "Content-Type: text/html; charset=iso-8859-1[\r][\n]"
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>401 Authorization Required</TITLE>
</HEAD><BODY>
<H1>Authorization Required</H1>
This server could not verify that you
are authorized to access the document
requested.  Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.<P>
<HR>
<ADDRESS>Apache/1.3.33 Server at thor Port 80</ADDRESS>
</BODY></HTML>
前節の実行例と同じURLに対してGET要求をしている. preemptiveモードだと,最初のGET要求時にいきなり認証情報を送信している.
2005-08-08 15:55:58,598 DEBUG [main] header Wire 69 - >> "GET /~matsu/hogedir/ HTTP/1.1[\r][\n]"
2005-08-08 15:55:58,646 DEBUG [main] header Wire 69 - >> "Authorization: Basic aG9nZTpob2dl[\r][\n]"
一回目の要求では,たまたまうまくいったが,レルムを特定できないので,サーバ,ポートが合致するスコープの最初の認証情報(レルムはHOGEFUSER)を送信している. 二回目ではレルムがFUGAUSERの認証情報が必要なので,最初の認証情報を無視されて,non-preemptiveモードと同様の動きとなっている.
2005-08-08 15:55:58,696 DEBUG [main] header Wire 69 - >> "GET /~matsu/fugadir/ HTTP/1.1[\r][\n]"
2005-08-08 15:55:58,698 DEBUG [main] header Wire 69 - >> "Authorization: Basic aG9nZTpob2dl[\r][\n]"
2005-08-08 15:55:58,699 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 15:55:58,700 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 15:55:58,700 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 15:55:58,703 DEBUG [main] header Wire 69 - << "HTTP/1.1 401 Authorization Required[\r][\n]"
2005-08-08 15:55:58,705 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 06:55:58 GMT[\r][\n]"
2005-08-08 15:55:58,707 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 15:55:58,708 DEBUG [main] header Wire 69 - << "WWW-Authenticate: Basic realm="FUGAUSER"[\r][\n]"
三回目の例は前節同様
method.setDoAuthentication(false);
とした場合の動作である. preemptiveモードによって最初に認証情報が送信されるが,二回目同様レルム不一致なので,レルムに応じた認証情報を送信する必要があるが,上記設定により認証を送信できなくて認証エラーとなる. preemptiveモード設定による認証情報の送信は実行される点に注意. したがって,preemptiveモードで送信される認証情報のレルムさえ合致すれば,
method.setDoAuthentication(false);
でも認証される.
前節までは,認証情報をHttpClient生成後に直接設定していた. これ以外に,サーバから認証情報を要求された際に認証情報を生成するCredentialsProviderを設定することで,認証する方法がある. サンプルでは,
client.getParams().setParameter(CredentialsProvider.PROVIDER, new ConsoleProvider());
が該当する. この操作段階では,HttpClientには認証情報は設定されておらず,サーバから認証情報を要求された際に,ここで設定したCredentialProviderから認証情報を取得してサーバに送信する動きとなる. CredentialProviderはインタフェースであり,設定するオブジェクトはこのインタフェースを実装していなければならない. CredentialProviderでは,以下のメソッドを実装する必要がある.
public Credentials getCredentials(AuthScheme scheme, String host, int port, boolean proxy)
    throws CredentialsNotAvailableException
本来なら,引数のscheme,host,port,proxy(Httpプロキシの認証か否か)を元に認証情報を設定していく. CredentialProviderのサンプルの実装クラスConsoleProviderを以下に示す.
これを使用した実行結果は以下.
$> java -jar httpclientsample.jar 2 http://thor/~matsu/hogedir http://thor/~matsu/fugadir http://thor/~matsu/fugadir
2005-08-08 17:11:33,790 DEBUG [main] header Wire 69 - >> "GET /~matsu/hogedir HTTP/1.1[\r][\n]"
2005-08-08 17:11:33,828 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 17:11:33,832 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 17:11:33,833 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 17:11:33,842 DEBUG [main] header Wire 69 - << "HTTP/1.1 401 Authorization Required[\r][\n]"
2005-08-08 17:11:33,846 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 08:11:33 GMT[\r][\n]"
2005-08-08 17:11:33,847 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 17:11:33,848 DEBUG [main] header Wire 69 - << "WWW-Authenticate: Basic realm="HOGEUSER"[\r][\n]"
2005-08-08 17:11:33,849 DEBUG [main] header Wire 69 - << "Transfer-Encoding: chunked[\r][\n]"
2005-08-08 17:11:33,849 DEBUG [main] header Wire 69 - << "Content-Type: text/html; charset=iso-8859-1[\r][\n]"
proxy = false
realm = HOGEUSER / schemeName = basic
UserName = hoge
Password = hoge

2005-08-08 17:11:35,330 DEBUG [main] header Wire 69 - >> "GET /~matsu/hogedir HTTP/1.1[\r][\n]"
2005-08-08 17:11:35,331 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 17:11:35,332 DEBUG [main] header Wire 69 - >> "Authorization: Basic aG9nZTpob2dl[\r][\n]"
2005-08-08 17:11:35,333 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 17:11:35,334 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 17:11:35,336 DEBUG [main] header Wire 69 - << "HTTP/1.1 301 Moved Permanently[\r][\n]"
2005-08-08 17:11:35,337 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 08:11:35 GMT[\r][\n]"
2005-08-08 17:11:35,338 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 17:11:35,338 DEBUG [main] header Wire 69 - << "Location: http://thor/~matsu/hogedir/[\r][\n]"
2005-08-08 17:11:35,339 DEBUG [main] header Wire 69 - << "Transfer-Encoding: chunked[\r][\n]"
2005-08-08 17:11:35,342 DEBUG [main] header Wire 69 - << "Content-Type: text/html; charset=iso-8859-1[\r][\n]"
2005-08-08 17:11:35,352 DEBUG [main] header Wire 69 - >> "GET /~matsu/hogedir/ HTTP/1.1[\r][\n]"
2005-08-08 17:11:35,354 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 17:11:35,355 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 17:11:35,357 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 17:11:35,360 DEBUG [main] header Wire 69 - << "HTTP/1.1 401 Authorization Required[\r][\n]"
2005-08-08 17:11:35,365 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 08:11:35 GMT[\r][\n]"
2005-08-08 17:11:35,365 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 17:11:35,366 DEBUG [main] header Wire 69 - << "WWW-Authenticate: Basic realm="HOGEUSER"[\r][\n]"
2005-08-08 17:11:35,368 DEBUG [main] header Wire 69 - << "Transfer-Encoding: chunked[\r][\n]"
2005-08-08 17:11:35,368 DEBUG [main] header Wire 69 - << "Content-Type: text/html; charset=iso-8859-1[\r][\n]"
2005-08-08 17:11:35,372 DEBUG [main] header Wire 69 - >> "GET /~matsu/hogedir/ HTTP/1.1[\r][\n]"
2005-08-08 17:11:35,373 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 17:11:35,374 DEBUG [main] header Wire 69 - >> "Authorization: Basic aG9nZTpob2dl[\r][\n]"
2005-08-08 17:11:35,374 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 17:11:35,378 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 17:11:35,381 DEBUG [main] header Wire 69 - << "HTTP/1.1 200 OK[\r][\n]"
2005-08-08 17:11:35,383 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 08:11:35 GMT[\r][\n]"
2005-08-08 17:11:35,383 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 17:11:35,384 DEBUG [main] header Wire 69 - << "Last-Modified: Sun, 07 Aug 2005 17:09:23 GMT[\r][\n]"
2005-08-08 17:11:35,385 DEBUG [main] header Wire 69 - << "ETag: "19f448-29-42f64043"[\r][\n]"
2005-08-08 17:11:35,389 DEBUG [main] header Wire 69 - << "Accept-Ranges: bytes[\r][\n]"
2005-08-08 17:11:35,390 DEBUG [main] header Wire 69 - << "Content-Length: 41[\r][\n]"
2005-08-08 17:11:35,391 DEBUG [main] header Wire 69 - << "Content-Type: text/html[\r][\n]"
<html>
<body>
PAGE HOGE
</body>
</html>


2005-08-08 17:11:35,396 DEBUG [main] header Wire 69 - >> "GET /~matsu/fugadir HTTP/1.1[\r][\n]"
2005-08-08 17:11:35,397 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 17:11:35,398 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 17:11:35,399 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 17:11:35,402 DEBUG [main] header Wire 69 - << "HTTP/1.1 401 Authorization Required[\r][\n]"
2005-08-08 17:11:35,404 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 08:11:35 GMT[\r][\n]"
2005-08-08 17:11:35,404 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 17:11:35,405 DEBUG [main] header Wire 69 - << "WWW-Authenticate: Basic realm="FUGAUSER"[\r][\n]"
2005-08-08 17:11:35,405 DEBUG [main] header Wire 69 - << "Transfer-Encoding: chunked[\r][\n]"
2005-08-08 17:11:35,406 DEBUG [main] header Wire 69 - << "Content-Type: text/html; charset=iso-8859-1[\r][\n]"
proxy = false
realm = FUGAUSER / schemeName = basic
UserName = exception
org.apache.commons.httpclient.auth.CredentialsNotAvailableException: failed to getCredentials
        at org.fireproject.httpclientsample.ConsoleProvider.getCredentials(ConsoleProvider.java:37)
        at org.apache.commons.httpclient.HttpMethodDirector.promptForCredentials(HttpMethodDirector.java:860)
        at org.apache.commons.httpclient.HttpMethodDirector.processWWWAuthChallenge(HttpMethodDirector.java:719)
        at org.apache.commons.httpclient.HttpMethodDirector.processAuthenticationResponse(HttpMethodDirector.java:651)
        at org.apache.commons.httpclient.HttpMethodDirector.executeMethod(HttpMethodDirector.java:190)
        at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:396)
        at org.apache.commons.httpclient.HttpClient.executeMethod(HttpClient.java:324)
        at org.fireproject.httpclientsample.HelloHttpClient.processGet(HelloHttpClient.java:95)
        at org.fireproject.httpclientsample.HelloHttpClient.main(HelloHttpClient.java:43)
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>401 Authorization Required</TITLE>
</HEAD><BODY>
<H1>Authorization Required</H1>
This server could not verify that you
are authorized to access the document
requested.  Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.<P>
<HR>
<ADDRESS>Apache/1.3.33 Server at thor Port 80</ADDRESS>
</BODY></HTML>

2005-08-08 17:11:38,442 DEBUG [main] header Wire 69 - >> "GET /~matsu/fugadir HTTP/1.1[\r][\n]"
2005-08-08 17:11:38,443 DEBUG [main] header Wire 69 - >> "User-Agent: Jakarta Commons-HttpClient/3.0-rc3[\r][\n]"
2005-08-08 17:11:38,444 DEBUG [main] header Wire 69 - >> "Host: thor[\r][\n]"
2005-08-08 17:11:38,450 DEBUG [main] header Wire 69 - >> "[\r][\n]"
2005-08-08 17:11:38,460 DEBUG [main] header Wire 69 - << "HTTP/1.1 401 Authorization Required[\r][\n]"
2005-08-08 17:11:38,472 DEBUG [main] header Wire 69 - << "Date: Mon, 08 Aug 2005 08:11:38 GMT[\r][\n]"
2005-08-08 17:11:38,476 DEBUG [main] header Wire 69
  - << "Server: Apache/1.3.33 (Debian GNU/Linux) mod_ssl/2.8.22 OpenSSL/0.9.7d mod_jk/1.2.5[\r][\n]"
2005-08-08 17:11:38,481 DEBUG [main] header Wire 69 - << "WWW-Authenticate: Basic realm="FUGAUSER"[\r][\n]"
2005-08-08 17:11:38,481 DEBUG [main] header Wire 69 - << "Transfer-Encoding: chunked[\r][\n]"
2005-08-08 17:11:38,483 DEBUG [main] header Wire 69 - << "Content-Type: text/html; charset=iso-8859-1[\r][\n]"
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>401 Authorization Required</TITLE>
</HEAD><BODY>
<H1>Authorization Required</H1>
This server could not verify that you
are authorized to access the document
requested.  Either you supplied the wrong
credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.<P>
<HR>
<ADDRESS>Apache/1.3.33 Server at thor Port 80</ADDRESS>
</BODY></HTML>
やはり三回GETメソッドを送信している. サーバから認証情報を要求されると,コンソールから入力を要求する. 一回目は正しい認証情報を入力した. 入力認証情報をもとに一度GETを飛ばすともう一度サーバから認証情報を要求され,今度は先程入力した認証情報を自動で送信している. 一見無駄な動きに見えるが,サーバがそう動くのだから,しようがないのだろうか. 二回目の入力ではユーザ名にexceptionと入力した. 先述のサンプルコードでは,ユーザ名にexceptionと入力すると,CredentialsNotAvailableExceptionを投げるようにしている. 三回目はやはり
method.setDoAuthentication(false);
により認証失敗している.
matsu(C)
Since 2002
Mail to matsu