HTTP認証

概要

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

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

Authenticatorクラスの使用方法

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

java.net.Authenticatorの拡張

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

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

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

認証の有効化

オーセンティケータの適切な実装クラスを定義し、次を呼び出すことにより認証を有効にします。
        Authenticator.setDefault (authinstance);

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

使用される認証スキームの制御

サーバーがクライアントの認証を必要とする場合、そのサーバーは多くのスキームをクライアントに提案し(例: ダイジェストおよび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は、プロキシまたはサーバーで使用できますが、同時に使用することはできません。プロキシで使用されている場合、これはサーバー認証用に使用できません。これは、プロトコルが実際に個々のHTTP相互作用ではなくTCP接続の認証を行うからです。

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

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

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

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

ネゴシエーションは、どのようなGSS認証メカニズムもHTTP認証プロトコルとして使用できるスキームです。現在、このスキームではKerberosとNTLMだけがサポートされています。NTLMについてはすでに上で説明しているため、このセクションでは、HTTP認証用Kerberosのセット・アップ方法についてのみ説明します。

Kerberos 5の構成

SPNEGOメカニズムはJGSSを呼び出し、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モジュールにユーザー名とパスワードを指定できます(つまり、資格キャッシュは使用できません)。オーセンティケータでチェックする必要がある認証情報は、getRequestingScheme()を使用して取得可能なスキームのみです。値は「Negotiate」である必要があります。つまり、オーセンティケータ実装は次のようになります。
    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 (krb5user,
                            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に記録されていない、オーセンティケータから提供されるユーザー名とパスワードが間違っているなど)、2番目に強力なスキームが自動的に使用されます。注意: http.auth.preferenceがSPNEGOまたはKerberosに設定されている場合、失敗する場合でも単にネゴシエーション・スキームを試行することが要求されていると想定されます。他のどのようなスキームにもフォールバックせず、プログラムによってHTTP応答から401または407のエラーを受け取ることを通知するIOExceptionがスローされます。

たとえば、Active Directory内のWindowsサーバーで稼動中のIISサーバーがあるとします。このサーバー上のWebページは、統合Windows認証によって保護されるように構成されています。つまり、サーバーはネゴシエーションと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 = "username"; // your account name
    static final String kpass = password; // retrieve password for your 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 © 1993, 2020, Oracle and/or its affiliates. All rights reserved.