第 VI 部:HTTP/SPNEGO 認証

課題 9:HTTP/SPNEGO 認証の使用

HTTP SPNEGO とは

HTTP SPNEGO は、HTTP 通信で Negotiate 認証方式をサポートしています。SPNEGO は、次のタイプの認証をサポートしています。

Web 認証

Web サーバーは次のように応答します。

       HTTP/1.1 401 Unauthorized
       WWW-Authenticate: Negotiate

クライアントは、次のヘッダーを送信する必要があります。

       Authorization: Negotiate YY.....

これにより、クライアントはサーバーの認証を受けます。

プロキシ認証

Web サーバーは次のように応答します。

       HTTP/1.1 407 Proxy Authentication Required
       Proxy-Authenticate: Negotiate

クライアントは、次のヘッダーを送信する必要があります。

       Proxy-Authorization: Negotiate YY.....

これにより、クライアントはプロキシサーバーの認証を受けます。

この機能は、両方のタイプの認証をサポートしています。

HTTP/SPNEGO 認証の使用方法

新規の機能に関連して新しく公開された API 関数はありません。ただし、正しく通信を行うには、いくつかの構成を行う必要があります。

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 (krb6user,
                            krb5pass));
            } else {
                ....
            }
        }
    }

-java.net.Authenticator の仕様では、ユーザー名とパスワードを同時に取得するように設計されています。このため、JAAS 構成ファイルに principal=xxx を指定しないでください。

スキーマの優先設定

クライアントは、システムプロパティー http.auth.preference を指定して、サーバーが特定のスキーマを要求するかぎりそのスキーマが常に使用されるように指定できます。このシステムプロパティーに対して「SPNEGO」または「Kerberos」を使用できます。「SPNEGO」は、GSS/SPNEGO 機構を使用して Negotiate スキーマに応答します。「Kerberos」は、GSS/Kerberos 機構を使用して Negotiate スキーマに応答します。通常、Microsoft 製品に対して認証を行う場合に「SPNEGO」を使用できます。値「Kerberos」も Microsoft サーバーに対して動作します。Kerberos は、Negotiate は認識するが SPNEGO は認識しないサーバーに対してのみ使用する必要があります。

http.auth.preference が設定されていない場合、選択される内部順序は次のようになります。

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

フォールバック

サーバーが Negotiate を含む複数の認証方式を提供している場合、前述のセクションで説明されている処理順序に従って、Java は Negotiate スキームを試行します。ただし、このプロトコルが正常に確立されない場合 (たとえば、kerberos 構成が正しくない、サーバーのホスト名が KDC 主体 DB に記録されていない、オーセンティケータによって指定されたユーザー名とパスワードが間違っているなど)、2 番目に強力なスキームが自動的に使用されます。

-http.auth.preference が SPNEGO または Kerberos に設定されている場合、SPNEGO では、失敗する場合でも Negotiate スキームを試行すると見なされます。SPNEGO はその他のスキーマにフォールバックしません。プログラムは IOException をスローし、HTTP 応答から 401 または 407 エラーを受信したことを通知します。

Active Directory 内の Windows サーバーで IIS サーバーを実行しているとします。このサーバー上の Web ページは、統合 Windows 認証によって保護されるように構成されています。つまり、サーバーは Negotiate と 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"; // 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); } }

krb.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>