…ためには色々面倒な実装が必要なのかと調べてみれば、実はそうでもなかった、というお話。
NTLM 認証の設定
IIS マネージャでファイルもしくはディレクトリのプロパティを開き、
[ディレクトリセキュリティ(ファイルセキュリティ)] -> 認証とアクセス制御の[編集] ->
[匿名アクセスを有効にする]のチェックを外し、[総合 Windows 認証]にチェックを入れる。
この状態でブラウザからアクセスするとユーザ名、パスワードを入力させる認証ダイアログが表示される。
Commons HttpClient で NTLM 認証に対応する
Commons HttpClient (3系)で NTLM 認証に対応するには、NTCredentials を使用する。
サーバに対する NTLM 認証に対応するには以下のようにする。
 public void ntlmExecute() throws IOException {
  HttpClient client = new HttpClient();
  
  client.getState().setCredentials(
    new AuthScope(SCOPE_HOST, SCOPE_PORT),
    new NTCredentials(USERNAME, PASSWORD, HOST, DOMAIN));
  
  HttpMethod method = new PostMethod(URL);
  int result = client.executeMethod(method);
  System.out.println(result);
  
  BufferedReader reader = null;
  try {
   reader = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream()));
   for (String line = reader.readLine() ; line != null ; line = reader.readLine()) {
    System.out.println(line);
   }
  } finally {
   if (reader != null) reader.close();
  }
 }
プロキシサーバに対する NTLM 認証に対応するには以下のようにする。
 public void ntlmProxyExecute() throws IOException {
  HttpClient client = new HttpClient();
  
  client.getHostConfiguration().setProxy(PROXY_HOST, PROXY_PORT);
  client.getState().setProxyCredentials(
    new AuthScope(SCOPE_HOST, SCOPE_PORT),
    new NTCredentials(USERNAME, PASSWORD, HOST, DOMAIN));
  
  HttpMethod method = new GetMethod(URL);
  int result = client.executeMethod(method);
  System.out.println(result);
  
  BufferedReader reader = null;
  try {
   reader = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream()));
   for (String line = reader.readLine() ; line != null ; line = reader.readLine()) {
    System.out.println(line);
   }
  } finally {
   if (reader != null) reader.close();
  }
 }
SOAP Webサービスクライアントを作ろう(Apache Axis 編)で書いた通り、
HTTP1.1 に対応させるために Commons HttpClient を使用したため、
上のコードを応用すれば Axis でもイケるだろうか…と調べてみた。
Apache Axis で NTLM 認証に対応する
NTLM 認証が設定されたエンドポイントに対してリクエストを送ると、以下のフォルトが返る。
- ntlm authentication scheme selected
- No credentials available for NTLM @<ホスト>:<ポート>
Exception in thread "main" AxisFault
 faultCode: {http://xml.apache.org/axis/}HTTP
 faultSubcode: 
 faultString: (401)Unauthorized
 faultActor: 
 faultNode: 
 faultDetail: 
CommonsHTTPSender から何とか HttpState を取り出して NTCredentials をセットできないものかと
CommonsHTTPSender のソースを眺めてみたところ、
既に NTCredentials をセットするコードが含まれていた。
MessageContext にセットされたユーザ名がドメインを含む表記だった場合、NTLM 認証用とみなしているようだ。
さらに、プロキシサーバの場合は TransportClientProperties からユーザ名などを取得していて、
実装クラス DefaultHTTPTransportClientProperties を見てみると
システムプロパティ「http.proxyHost」「http.proxyPort」「http.proxyUser」「http.proxyPassword」から値を参照しているため、
システムプロパティに適切な値を設定してあげれば Webサービスクライアント側のコードの変更は不要なようだ。
サーバに対する NTLM 認証に対応するのであれば、
自動生成したスタブを使用する場合、独自に SOAP リクエストを構築する場合でそれぞれ設定箇所が異なるが、
いずれにしてもユーザ名、パスワードを設定するだけで特別な処理は不要だった。
スタブを使用する場合
スタブを使用しない場合
設定が必要なのはユーザ名、パスワード、ドメインのみ。(「ドメイン\ユーザ名」の形でユーザ名にセットする)
NTCredentials にセットするホスト名は CommonsHTTPSender 内部で NetworkUtils を使用して取得してくれるので、
外部から設定する必要はない。

Copyright© 2011-2021 Shunsuke Otani All Right Reserved .