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

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

スキームの優先設定

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

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

ネゴシエーションがサポートされる場合は常に 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 認証によって保護されるように構成されています。つまり、サーバーはネゴシエーションと 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>

Copyright © 1993, 2013, Oracle and/or its affiliates. All rights reserved.