Java

HTTP 認証

ドキュメントの目次

概要

HTTP プロトコルハンドラは、多くの認証方式を実装しています。Sun による Java SE Version 6 の実装では、次の方式がサポートされています。 これらの各方式の詳細については次に説明しますが、通常はアプリケーションコードによってほぼ同じ手法で使用されます。java.net.Authenticator クラスにより、認証を有効にして、個々の認証方式に使用するユーザー名とパスワードが保存されている場所にアクセスできるようになります。

一般に、認証方式はすべてプロキシとサーバーの両方によって機能します。一部のもの (基本およびダイジェスト) は、プロキシとサーバーで同時に使用できます。プロキシとサーバーの認証を区別する方法については次を参照してください。

Authenticator クラスの使用方法

Authenticator とは、アプリケーションで拡張された abstract クラスを示しており、一度インストールされると、認証の相互作用に必要なユーザー名とパスワードを取得するために呼び出されます。

java.net.Authenticator の拡張

アプリケーションコードにより、getPasswordAuthentication() メソッドをオーバーライドする必要があります。なお、このメソッドは abstract ではなく、デフォルト実装は処理を行いません。次に最も単純な例を示します。

    class MyAuthenticator extends Authenticator {

        public PasswordAuthentication getPasswordAuthentication () {
            return new PasswordAuthentication ("user", "pass1".toCharArray());
        }
    }

この例では、各 HTTP 認証の相互作用に使用するユーザー名「user」とパスワード「pass1」を返します。さらに実践的な例では、java.net.Authenticator の別のメソッドを使用して認証を必要とする HTTP 要求について詳細情報を取得します。資格の要求をそれぞれ処理する方法について決定するには、getPasswordAuthentication() を実装して、次のメソッドのいずれかを呼び出します。

認証の有効化

Authenticator の適切な実装クラスを定義し、次を呼び出すことにより認証を有効にします。

	Authenticator.setDefault (authinstance);

ここで authinstance は、すでに宣言済みの実装クラスのインスタンスです。これが呼び出されない場合、認証は無効になり、サーバー認証エラーが IOException オブジェクト経由でユーザーコードに返されます。HTTP 実装は、インストールされると、可能な場合に、キャッシュされた資格経由またはシステムから取得可能な資格経由で自動認証を試行します。正しい資格が使用できない場合は、ユーザーの Authenticator を呼び出して、この資格を取得できます。

使用される認証方式の制御

サーバーがクライアントの認証を必要とする場合、そのサーバーは多くの方式をクライアントに提案し (例: ダイジェストおよび NTLM)、クライアントはその中から方式を選択できます。通常、アプリケーションでは、使用する方式の種類は考慮されず、実装においてもっとも強力な (もっとも安全な) プロトコルが透過的に自動選択されます。

特定の方式を必ず使用する必要がある場合は、次のシステムプロパティーを設定してデフォルト時の動作を修正できます。

	-Dhttp.auth.preference="scheme"

コマンド行でこのプロパティーの設定を行う場合は、-D を指定します。「http.auth.preference」はプロパティー名であり、「scheme」は使用する方式名です。提案した方式のリストにサーバーがこの方式を含めない場合は、デフォルト設定が有効となります。

各認証方式の詳細

HTTP 基本認証

基本認証は、単純ですが、RFC 2317 で定義されている安全度が高いとは言えない認証方式です。ユーザー名とパスワードは Base 64 でエンコーディングされているため、パケットデータにアクセスするユーザーはこれらの情報を簡単に取得することができます。基本認証のセキュリティーは、HTTPS を採用し、要求と応答を暗号化することによって改善できます。

getRequestingPrompt() メソッドは、サーバーが提供するような基本認証レルムを返します。

HTTP ダイジェスト

ダイジェストは、MD5 ハッシュアルゴリズムを採用し、ユーザー名とパスワードの暗号化ハッシュに基づく比較的安全な方式です。また、ダイジェストにより、サーバーは、共有の秘密 (パスワード) を認識することをクライアントに証明することができます。この機能は、すべてのサーバーでサポートされているわけではないので、通常は無効となっています。次のシステムプロパティーで切り替えが可能です。

	-Dhttp.auth.digest.validateServer="true"
	-Dhttp.auth.digest.validateProxy="true"

getRequestingPrompt() メソッドは、サーバーが提供するようなダイジェスト認証レルムを返します。

NTLM

NTLM は、Microsoft によって定義されている方式です。この方式は、基本認証に比べて安全性の高いものとなっていますが、ダイジェスト認証ほどではありません。NTLM は、プロキシまたはサーバーで使用できますが、同時に使用することはできません。プロキシで使用されている場合、NTLM はサーバー認証用に使用できません。これは、プロトコルが実際に個々の HTTP 相互作用ではなく TCP 接続の認証を行うからです。

Microsoft Windows プラットフォームでは、NTLM 認証により、ユーザーの Authenticator オブジェクトを要求せずにシステムからユーザー資格の取得を試みます。このような資格をサーバーが受け入れない場合は、ユーザーの Authenticator が呼び出されます。

NTLM をサポートする以前に Authenticator クラスが定義されているため、NTLM ドメインフィールドの API をさらにサポートすることはできません。ドメインを指定する方法には、次の 3 つの方法があります。

  1. ドメインを指定しない。環境によっては、ドメインを実際に必要とせず、アプリケーションで指定する必要がない
  2. ユーザー名の前にドメイン名 + 円記号「\」をつけることで、ドメイン名をユーザー名内にエンコードする。この方法では、ユーザーがこの表記方法を使用しなければならないということを意識すれば、Authenticator クラスを使用する既存のアプリケーションを変更する必要がない
  3. ドメイン名を方法 2) で指定せず、システムプロパティー http.auth.ntlm.domain が定義されている場合、このプロパティーの値をドメイン名として使用できる

HTTP ネゴシエーション (SPNEGO)

HTTP ネゴシエーションは、いかなる GSS 認証機構も HTTP 認証プロトコルとして使用できる方式です。現在、この方式では Kerberos と NTLM だけがサポートされています。NTLM についてはすでに上で説明しているため、この節では、HTTP 認証用 Kerberos のセットアップ方法についてのみ説明します。

Kerberos 5 構成

SPNEGO 機構では JGSS を呼び出すため、実際の処理を行う際は代わりに Kerberos V5 ログインモジュールを呼び出します。Kerberos 5 構成が要求されています。この構成には次のものが含まれます。

            java -Djava.security.krb5.conf=krb5.conf \
                 -Djavax.security.auth.useSubjectCredsOnly=false \
                 ClassName

たとえば、次のように spnegoLogin.conf ファイルを指定できます。

          com.sun.security.jgss.krb5.initiate {
              com.sun.security.auth.module.Krb5LoginModule
                  required useTicketCache=true;
          };
また、次のようにして Java を実行します。
            java -Djava.security.krb5.conf=krb5.conf \
                 -Djava.security.auth.login.config=spnegoLogin.conf \
                 -Djavax.security.auth.useSubjectCredsOnly=false \
                 ClassName

ユーザー名とパスワードの取得

他のいかなる HTTP 認証方式と同様に、クライアントでは、カスタマイズされた java.net.Authenticator を提供して、ユーザー名とパスワードを必要とする場合 (つまり、利用可能な資格キャッシュが存在しない場合) はそれらを HTTP SPNEGO モジュールに送ることができます。使用中の Authenticator でチェックが必要な唯一の認証情報は、getRequestingScheme() を使用して取得できる方式です。値は「Negotiate」とする必要があります。

これは、使用中の Authenticator 実装が次のようになることを意味します。

    class MyAuthenticator extends Authenticator {

        public PasswordAuthentication getPasswordAuthentication () {
            if (getRequestingScheme().equalsIgnoreCase("negotiate")) {
                String krb5user;
                char[] krb5pass;
                // get krb5user and krb5pass in your own way
                ....
                return (new PasswordAuthentication (krb6user,
                            krb5pass));
            } else {
                ....
            }
        }
    }

注意: java.net.Authenticator の仕様に応じてユーザー名とパスワードを同時に取得するようになっているため、JAAS 構成ファイルで principal=xxx の指定は行わないでください。

方式の設定

クライアントでは引き続きシステムプロパティー http.auth.preference を提供して、一部の方式がサーバーから要求される間は常にその方式が使用されるようにします。このシステムプロパティーには、「SPNEGO」または「Kerberos」のいずれかを使用できます。「SPNEGO」は、GSS/SPNEGO 機構を使用してネゴシエーション方式に応答する場合、「Kerberos」は、GSS/Kerberos 機構を使用してネゴシエーション方式に応答する場合に選択します。通常、Microsoft 製品の認証には、「SPNEGO」を使用します。値「Kerberos」は、Microsoft サーバーにも対応しています。これは、ネゴシエーションは認識するが SPNEGO については対応していないサーバーに遭遇する場合にのみ必要となります。

http.auth.preference を設定していない場合は、内部の順番が次のようになります。

ネゴシエーションがサポートされている場合は、GSS/SPNEGO が常に選択されているため、Kerberos はこのリストに表示されません。

代替

最後の節に記載された処理の手順に応じて、サーバーで複数の認証方式 (ネゴシエーションを含む) を提供している場合、Java では、ネゴシエーション方式の検証を試みます。ただし、プロトコルを正常に確立できない場合 (kerberos の設定が正しくない、サーバーのホスト名が KDC 主体 DB に記録されていない、Authenticator から提供されるユーザー名とパスワードが間違っているなど)、2 番目に有力な方式が自動的に選択されます。

注意: http.auth.preference が SPNEGO または Kerberos に設定されている場合は、失敗しても、単にネゴシエーション方式を試行することが要求されていると想定されます。他のいかなる方式に対しても切り替えを行わず、HTTP 応答から 401 または 407 のエラーを受け取ることを表す IOException がスローされます。

たとえば、Active Directory 内の Windows サーバーで稼動中の IIS サーバーがあるとします。このサーバー上の Web ページは、Windows Integrated Security で保護されています。これは、サーバーがネゴシエーション認証と NTLM 認証の両方を要求することを意味します。

保護されたファイルを取得するために、次のファイルを用意する必要があります。

/********* RunHttpSpnego.java ***********/

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.net.URL;

public class RunHttpSpnego {

    static final String kuser = "dummy"; // your account name
    static final String kpass = "bogus"; // your password for the account

    static class MyAuthenticator extends Authenticator {
        public PasswordAuthentication getPasswordAuthentication() {
            // I haven't checked getRequestingScheme() here, since for NTLM
            // and Negotiate, the usrname and password are all the same.
            System.err.println("Feeding username and password for " + getRequestingScheme());
            return (new PasswordAuthentication(kuser, kpass.toCharArray()));
        }
    }

    public static void main(String[] args) throws Exception {
        Authenticator.setDefault(new MyAuthenticator());
        URL url = new URL(args[0]);
        InputStream ins = url.openConnection().getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(ins));
        String str;
        while((str = reader.readLine()) != null)
            System.out.println(str);
    }
}

/********* krb5.conf ***********/
[libdefaults]
    default_realm = AD.LOCAL
[realms]
    AD.LOCAL = {
        kdc = kdc.ad.local
    }

/********* login.conf ***********/
com.sun.security.jgss.krb5.initiate {
  com.sun.security.auth.module.Krb5LoginModule required doNotPrompt=false useTicketCache=true;
};

ここで RunHttpSpnego.java をコンパイルして次を実行します。

java -Djava.security.krb5.conf=krb5.conf \
    -Djava.security.auth.login.config=login.conf \
    -Djavax.security.auth.useSubjectCredsOnly=false \
    RunHttpSpnego \
    http://www.ad.local/hello/hello.html

次のように出力されます。

Feeding username and password for Negotiate
<h1>Hello, You got me!</h1>

事実、ドメインユーザーとして Windows マシンを稼働しているか、またはすでに kinit コマンドを発行して資格キャッシュを取得した Linux または Solaris マシンを稼働しています。MyAuthenticator クラスは完全に無視され、次のようにシンプルに出力されます。

<h1>Hello, You got me!</h1>

ユーザー名とパスワードが参照されないことを示しています。これは、いわゆるシングルサインオンです。

また、次のように実行して、

java RunHttpSpnego \
    http://www.ad.local/hello/hello.html

代替がどのように実行されるかを確認できます。この場合は、次のように表示されます。

Feeding username and password for ntlm
<h1>Hello, You got me!</h1>


Copyright © 2006 Sun Microsystems, Inc.All Rights Reserved.
フィードバック

 Sun Microsystems, Inc
Java Software