JAAS LoginユーティリティおよびJava GSS-APIを使用したセキュアなメッセージ交換
このチュートリアルでは、2つのサンプル・アプリケーションを使って、Java GSS-APIの使用方法を説明します。このAPIは、アプリケーション間のセキュアなメッセージ交換を可能にします。このチュートリアルで使用するサンプルのクライアント・アプリケーションおよびサーバー・アプリケーションは次の2つです。
ノート:
このチュートリアルでは、Java GSS-APIを使用した、JAASプログラミングなしのセキュアなメッセージ交換チュートリアルと同じクライアントおよびサーバーのアプリケーションを使用します。そのチュートリアルでは、JAAS (Java認証・承認サービス)プログラミングは不要です。その代わり、基盤となるメカニズムによってクレデンシャルの取得方法が決定されます。このチュートリアルでは、より複雑なログイン構成ファイルを使用します。
作業を開始する前に: 関連チュートリアルの紹介
このJava GSS-APIチュートリアルは、JAAS認証の最初のステップです。前のチュートリアルでは、JAASを使用してユーザー認証を行う方法と、JAASに必要なログイン構成ファイル(使用する基盤となる認証技術を指定する)の例を示しました。JAAS入門チュートリアルの「JAAS認証」のアプリケーションは、JAASメソッドを直接コールしました。「JAAS Loginユーティリティの使用」チュートリアルでは、アプリケーションをこの操作から解放するユーティリティ・プログラムの使用方法を示しました。このチュートリアルのクライアントおよびサーバー・アプリケーションでも同じユーティリティ・プログラムを使用しますので、あらかじめLoginユーティリティのチュートリアルの内容を確認してからこのチュートリアルに進むことをお薦めします。
この一連のチュートリアルでは、Kerberosを認証およびアプリケーションのセキュアな通信をサポートする基幹技術として使用しています。「Kerberos要件」を参照してください。
クライアントおよびサーバー・アプリケーションの概要
このチュートリアルで使用するアプリケーションの名前は、SampleClient
およびSampleServer
です。
それぞれ、このチュートリアルで提供するLoginユーティリティを実行して呼び出し、引数として、アプリケーションの名前(SampleClient
またはSampleServer
)と、続いてアプリケーションが必要とする引数をそれに渡します。Loginユーティリティは、JAAS LoginContextを使用して、Kerberosを使用するユーザーを認証します。最後に、Loginユーティリティはアプリケーション・クラス(ここではSampleClient
またはSampleServer
)のmain
メソッドを呼び出して、アプリケーションに引数を渡します。
次に、SampleClient
およびSampleServer
アプリケーションの実行方法のサマリーを示します。
- 引数に
SampleServer
、続いてSampleServer
プログラム用の引数を指定してLoginユーティリティを実行することにより、SampleServer
アプリケーションを実行します。Loginユーティリティにより、SampleServer
を実行するプリンシパルのパスワード入力が求められます。(「Kerberosユーザー名およびサービス・プリンシパル名」を参照)。認証完了後に、SampleServer
が実行されます。- 引数に注目し、クライアントからの接続を待機するポート番号を確認します。
- 指定されたポートでのクライアント接続を待機するServerSocketを作成します。
- 接続を待機します。
- 引数に
SampleClient
、続いてSampleClient
プログラム用の引数を指定してLoginユーティリティを実行することにより、SampleClient
アプリケーションを実行します(通常別のマシンを使用)。Loginユーティリティにより、Kerberos名およびパスワードの入力が求められます。認証完了後に、SampleClient
が実行されます。次を実行します- その引数を参照してください。(1)
SampleServer
を表すKerberosプリンシパルの名前。(Kerberosユーザー名およびサービス・プリンシパル名を参照)、(2)SampleServer
を実行中のホスト(マシン)の名前、(3)SampleServer
がクライアント接続を待機するポート番号。 - 引数として渡されたホストおよびポートを使用して、
SampleServer
へのソケット接続を試みます。
- その引数を参照してください。(1)
- ソケット接続が
SampleServer
により受け入れられます。両方のアプリケーションが、ソケット入力および出力ストリームからのDataInputStreamおよびDataOutputStreamを初期化して、将来のデータ交換に使用します。 SampleClient
およびSampleServer
は、それぞれGSSContextをインスタンス化し、以後のセキュアなデータ交換を可能にする共有コンテキストを確立します。- これで、
SampleClient
およびSampleServer
は、メッセージをセキュアに交換できます。 SampleClient
およびSampleServer
は、メッセージ交換の完了後に、クリーンアップ操作を実行します。
ノート:
このチュートリアルで使用するコードの詳細は、Java GSS-APIを使用した、JAASプログラミングなしのセキュアなメッセージ交換チュートリアルのSampleClientおよびSampleServerコードの項を参照してください。
Kerberosユーザー名およびサービス・プリンシパル名
このチュートリアルでは、ベースとなる認証およびセキュアな通信技術としてKerberos V5が使用されているため、ユーザーまたはサービスが要求される場合、常にKerberosスタイルのプリンシパル名が使用されます(プリンシパルを参照)。
たとえば、SampleClient
を実行する場合、ユーザー名の指定が求められます。Kerberosスタイルのユーザー名は、Kerberos認証用だけに割り当てられたユーザー名です。ベース・ユーザー名(mjones
など)、「@
」およびレルムの順序で構成されます(例、mjones@KRBNT-OPERATIONS.EXAMPLE.COM
)。
通常、SampleServer
などのサーバー・プログラムは、「サービス」を提供し、特定の「サービス・プリンシパル」に代わって実行されるプログラムと見なされます。SampleServer
のサービス・プリンシパル名が必要とされるのは、次の場合です。
SampleServer
の実行時に、適切なサービス・プリンシパルとしてログインする必要があります。このチュートリアルのログイン構成ファイルは、実際にサービス・プリンシパル名を指定します(Krb5LoginModuleのオプションとして)。このため、JAAS認証(Loginユーティリティによって実行される)は、そのサービス・プリンシパルのパスワードの指定のみをユーザーに求めます。適切なパスワードを指定すると、認証に成功し、サービス・プリンシパル名でPrincipalを含むSubjectが作成されます。その後に実行されるコード(SampleServer
コード)は、指定されたプリンシパルに代わって実行されたと見なされます。SampleClient
を実行する場合、引数の1つはサービス・プリンシパル名です。これは必須です。このため、SampleClient
は適切なサービスを使用してセキュリティ・コンテキストの確立を開始できます。
このドキュメント全体、および関連するログイン構成ファイルでは、service_principal@your_realm
は、環境内で使用される実際の名前に置き換えられるプレースホルダとして使用されます。サービス・プリンシパル名として、任意の Kerberosプリンシパルを実際に使用できます。このため、このチュートリアルを実行してみる場合、クライアント・ユーザー名とサービス・プリンシパル名の両方に自分のユーザー名を使用できます。
通常、本番稼動環境では、システム管理者は、サーバーを特定のプリンシパルのみで実行し、特定の名前を割り当てて使用します。たいてい、割り当てるKerberos形式のサービス・プリンシパル名は、次のようになります。
service_name/machine_name@realm;
たとえば、KRBNT-OPERATIONS.EXAMPLE.COM
というレルム内の「raven」という名前のマシンでnfsサービスを実行する場合、サービス・プリンシパル名は次のようになります
nfs/raven@KRBNT-OPERATIONS.EXAMPLE.COM
ただし、このようなマルチコンポーネント名は必須ではありません。ユーザー・プリンシパル名のような、シングルコンポーネント名も使用できます。たとえば、インストールによって、レルム内のすべてのftpサーバーで同じftpサービス・プリンシパルftp@realm
を使用する場合と、ftpサーバーごとに異なるftpプリンシパルを使用する(たとえば、マシンhost1
、host2
のftpプリンシパルがそれぞれftp/host1@realm
、ftp/host2@realm
となる)場合があります。
プリンシパル名にレルムを指定する必要がある場合
ユーザーまたはサービス・プリンシパル名のレルムがデフォルト・レルムの場合は(Kerberos要件を参照)、Kerberosにログインする際、ユーザー名を求めるプロンプトが表示された時点で、レルムを指定しないことも可能です。このため、たとえばユーザー名がmjones@KRBNT-OPERATIONS.EXAMPLE.COM
で、SampleClient
を実行する場合、ユーザー名が要求されたら、レルムを省略して単にmjones
と指定できます。名前はKerberosプリンシパル名のコンテキストで解釈され、必要に応じてデフォルトのレルムが付けられます。
GSSManagerのcreateName
メソッドにより、プリンシパル名がGSSNameに変換される場合にも、レルムの指定を省略できます。たとえば、SampleClient
の実行時に、引数の1つにサーバー・サービス・プリンシパル名を指定します。この場合、SampleClient
が名前をcreateName
メソッドなどに渡し、このメソッドが必要に応じてデフォルトのレルムを追加するため、名前を指定する際にレルムを省略できます。
これらのファイルのパーサーの動作は実装に依存する可能性があるため、ログイン構成ファイルでプリンシパル名が使用される場合は常にレルムを含めることをお薦めします。このような名前が使用される前にデフォルト・レルムを追加する場合と追加しない場合があり、その名前にレルムがない場合、後続のアクションが失敗することがあります。
ログイン構成ファイル
JAASを使用する場合は常に、使用する認証テクノロジをログイン構成ファイルに指定する必要があります。(ログイン構成ファイルの詳細は、付録B: JAASログイン構成ファイルを参照してください。)ログイン構成ファイルに、クライアント側が使用するエントリとサーバー側が使用するエントリの2つが含まれる場合、SampleClient
とSampleServer
の両方で同じログイン構成ファイルを使用できます。
このチュートリアルで使用するログイン構成ファイルcsLogin.conf
を、次に示します。
SampleClient {
com.sun.security.auth.module.Krb5LoginModule required;
};
SampleServer {
com.sun.security.auth.module.Krb5LoginModule required storeKey=true
principal="service_principal@your_realm";
};
各エントリの名前は、2つのトップレベル・アプリケーションSampleClient
およびSampleServer
のクラス名にそれぞれ一致します。これは、アプリケーション用のJAAS操作を実行するLoginユーティリティに渡される名前でもあることに留意してください。Loginユーティリティがログイン構成ファイル内で検索するエントリ名は、渡されたエントリ名と同じになります。
両方のエントリでは、ユーザー認証の成功のため、OracleのKerberos V5ログイン・モジュールを使用する必要があることが指定されています。Krb5LoginModuleが成功するのは、指定されたエンティティでのKerberos KDCへのログインが成功した場合だけです。SampleClient
の場合、ユーザーは名前とパスワードの入力を求められます。SampleServer
の場合、このログイン構成ファイルに名前(指定されたプリンシパル)が指定されているため、SampleServer
を実行するユーザーには、その名前で指定されたエンティティのパスワードの入力だけが求められます。認証が成功するには、正確なパスワードを指定する必要があります。
SampleServer
のエントリstoreKey=true
は、ログイン時に指定されたパスワードから秘密キーを計算すること、およびログインにより作成されたサブジェクトのprivateクレデンシャルに秘密キーを格納することを意味します。このキーは、SampleClient
とSampleServer
との間でセキュリティ・コンテキストを確立する際、相互認証に利用されます。
Krb5LoginModuleにはprincipal
オプションがあり、指定されたプリンシパル(エンティティ/ユーザー)だけが特定のプログラムにログインすることを指定するために使用できます。ここでは、SampleClient
エントリにプリンシパルが指定されていない(必要に応じて指定可能)ため、ユーザーはユーザー名およびパスワードの入力を求められます。有効なユーザー名およびパスワードを保持するユーザーならだれでもSampleClient
を実行できます。一方、SampleServer
は特定のプリンシパルを示します。通常、システム管理者は、サーバーを特定のプリンシパルとしてのみ実行することを好むためです。この場合、SampleServer
を実行するユーザーは、プリンシパルのパスワードの入力を求められ、認証が成功するには、正しいパスワードを指定する必要があります。
service_principal@your_realm
を、SampleServer
を表すサービス・プリンシパルの名前で置き換える必要があります。(「Kerberosユーザー名およびサービス・プリンシパル名」を参照)。
サーバーに秘密キーを含むキータブ・ファイルがある場合、次のJAASログイン・エントリを使用します。
SampleServer {
com.sun.security.auth.module.Krb5LoginModule required
principal="service_principal@your_realm"
storeKey=true useKeyTab=true keyTab=keytab.file.name
isInitiator=false;
};
キータブ・ファイルですでにキーを指定しているため、パスワードは要求されません。キータブ・ファイルに複数のサービス・プリンシパルのキーが含まれ、サーバーがこれらすべてのサービス・プリンシパルとして機能するように設計されている場合は、プリンシパル・エントリを次のように設定できます。
principal=*
Krb5LoginModuleに渡すことができるすべてのオプションの詳細は、Krb5LoginModule Javadoc APIドキュメントを参照してください。
SampleClientおよびSampleServerプログラムの実行
SampleClient
およびSampleServer
プログラムを実行するには、次の操作を行います。
SampleServerの実行準備
SampleServer
の実行準備では、次の操作を行います。
- 次のファイルを、
SampleServer
を実行するマシンからアクセス可能なディレクトリにコピーします。Login.java
ソース・ファイル。SampleServer.java
ソース・ファイル。csLogin.conf
ログイン構成ファイル。
csLogin.conf
のservice_principal@your_realm
を、SampleServer
を表すサービス・プリンシパルの名前で置き換えます(Kerberosユーザー名およびサービス・プリンシパル名を参照)。Login.java
とSampleServer.java
をコンパイルします。javac Login.java SampleServer.java
Login.java
には2つのクラスが含まれるため、Login.java
をコンパイルするとLogin.class
およびMyAction.class
が生成されます。Login.class and MyAction.class
を含むLogin.jar
という名前のJARファイルを作成します。jar -cvf Login.jar Login.class MyAction.class
SampleServer.class
を含むSampleServer.jar
という名前のJARファイルを作成します。jar -cvf SampleServer.jar SampleServer.class
SampleClientの実行準備
SampleClient
の実行準備では、次の操作を行います。
- 次のファイルを、
SampleClient
を実行するマシンからアクセス可能なディレクトリにコピーします。Login.java
ソース・ファイル。SampleClient.java
ソース・ファイル。csLogin.conf
ログイン構成ファイル。
Login.java
とSampleClient.java
をコンパイルします。javac Login.java SampleClient.java
Login.class and MyAction.class
を含むLogin.jar
という名前のJARファイルを作成します。jar -cvf Login.jar Login.class MyAction.class
SampleClient.class
を含むSampleClient.jar
という名前のJARファイルを作成します。jar -cvf SampleClient.jar SampleClient.class
SampleServerの実行
SampleClient
を実行する前に、必ずSampleServer
を実行してください。SampleClient
はSampleServer
へのソケット接続を試みるため、SampleServer
が稼動していないとソケット接続が受け付けられず、失敗します。
SampleServer
を実行する場合、SampleServerを稼動する予定のマシンで実行してください。このマシン名(ホスト名)は、SampleClient
の引数として指定します。サービス・プリンシパル名は、ログイン構成ファイルなど、いくつかの場所に表示されます。
SampleServer
の実行用に準備したディレクトリに移動します。次を指定して、Login
クラスを実行します。
- 適切な
-classpath
節(Login.jar
およびSampleServer.jar
JARファイル内のクラスを検索するため)。 -Djava.security.krb5.realm=<your_realm>
(使用するKerberosレルム)。たとえば、レルムがKRBNT-OPERATIONS.EXAMPLE.COM
の場合、-Djava.security.krb5.realm=KRBNT-OPERATIONS.EXAMPLE.COM
のように指定します。-Djava.security.krb5.kdc=<your_kdc>
(使用するKerberos KDC)。たとえば、KDCがsamplekdc.example.com
の場合、-Djava.security.krb5.kdc=samplekdc.example.com
のように指定します。-Djava.security.auth.login.config=csLogin.conf
。使用するログイン構成ファイルとしてcsLogin.conf
を指定します。
ノート:
java.security.auth.login.config
システム・プロパティで、(等号を2つ(==
)ではなく)等号を1つ(=
)使用している場合、このシステム・プロパティおよびjava.security
ファイルの両方で指定された構成が使用されます。Loginの引数として、アプリケーションの名前(ここではSampleServer
)を渡します。次に、アプリケーションに必要なすべての引数を追加します。SampleServer
の場合、クライアント接続の待機に使用するポート番号を指定する単一の引数です。通常は使用しない大きなポート番号であれば、どの番号でも選択できます。(例、4444)。
次に、Windows、LinuxおよびmacOSで使用する完全なコマンドを示します。クラス・パス項目の区切りとして、LinuxおよびmacOSではコロンを使用するのに対し、Windowsではセミコロンを使用する点のみが異なります。
ノート:
これらのコマンドの、<port_number>
を適切なポート番号に、<your_realm>
を使用するKerberosレルムに、<your_kdc>
を使用するKerberos KDCにそれぞれ置き換えてください。
次に、Windowsのコマンドを示します。
java -classpath Login.jar;SampleServer.jar
-Djava.security.krb5.realm=<your_realm>
-Djava.security.krb5.kdc=<your_kdc>
-Djava.security.auth.login.config=csLogin.conf
Login SampleServer <port_number>
次に、LinuxおよびmacOSのコマンドを示します。
java -classpath Login.jar:SampleServer.jar
-Djava.security.krb5.realm=<your_realm>
-Djava.security.krb5.kdc=<your_kdc>
-Djava.security.auth.login.config=csLogin.conf
Login SampleServer <port_number>
コマンド全体を1行で入力してください。ここでは、読みやすくするために複数行に分けて表示してあります。システムに対しコマンドが長すぎる場合は、.bat
ファイル(Windowsの場合)または.sh
ファイル(LinuxおよびmacOSの場合)に記述し、そのファイルを実行して、コマンドを実行する必要がある場合があります。
サービス・プリンシパルのKerberosパスワードの入力が求められます。ログイン構成ファイルで指定された基盤となるKerberos認証メカニズムにより、サービス・プリンシパルのKerberosへのログインが行われます。認証が成功すると、SampleServer
のコードがサービス・プリンシパルに代わって実行されます。このコードは、指定されたポート上でソケット接続を待機します。
ログイン時のトラブルシューティングは、ログインのトラブルシューティングを参照してください。
SampleClientの実行
SampleClient
を実行するため、SampleClient
の実行準備を行ったディレクトリに移動します。次に、次を指定して、Login
クラスを実行します。
- 適切な
-classpath
節(Login.jar
およびSampleClient.jar
JARファイル内のクラスを検索するため)。 -Djava.security.krb5.realm=<your_realm>
(使用するKerberosレルム)。-Djava.security.krb5.kdc=<your_kdc>
(使用するKerberos KDC)。-Djava.security.auth.login.config=csLogin.conf
。使用するログイン構成ファイルとしてcsLogin.conf
を指定します。
Loginに、アプリケーションの名前(SampleClient
)、その後SampleClient
に必要な引数を渡します。SampleClient
の引数は、(1) SampleServer
を表すサービス・プリンシパルのKerberos名(Kerberosユーザー名およびサービス・プリンシパル名を参照)、(2) SampleServer
を実行するホスト(マシン)の名前、(3) SampleServer
がクライアント接続を待機するポート番号です。
次に、Windows、LinuxおよびmacOSで使用する完全なコマンドを示します。
ノート:
重要: これらのコマンドの、<service_principal>
、<host>
、<port_number>
、<your_realm>
および<your_kdc>
を、適切な値で置き換えてください(ポート番号は、SampleServer
の引数として渡したポート番号と同じにする必要があります)。値を引用符で囲む必要はありません。
次に、Windowsのコマンドを示します。
java -classpath Login.jar;SampleClient.jar
-Djava.security.krb5.realm=<your_realm>
-Djava.security.krb5.kdc=<your_kdc>
-Djava.security.auth.login.config=csLogin.conf
Login SampleClient <service_principal> <host> <port_number>
次に、LinuxおよびmacOSのコマンドを示します。
java -classpath Login.jar:SampleClient.jar
-Djava.security.krb5.realm=<your_realm>
-Djava.security.krb5.kdc=<your_realm>
-Djava.security.auth.login.config=csLogin.conf
Login SampleClient <service_principal> <host> <port_number>
コマンド全体を1行で入力してください。ここでは、読みやすくするために複数行に分けて表示してあります。SampleServer
を実行するコマンドと同様、コマンド・ウィンドウに直接入力するにはコマンドが長すぎる場合、.bat
ファイル(Windowsの場合)または.sh
ファイル(Linuxの場合およびmacOSの場合)に配置して、そのファイルを実行してください。
入力が求められたら、Kerberosユーザー名およびパスワードを入力します。ログイン構成ファイルで指定された基盤となるKerberos認証メカニズムにより、Kerberosへのログインが行われます。認証が成功すると、SampleClient
のコードがユーザーに代わって実行されます。このコードは、SampleServer
とのソケット接続を要求します。SampleServer
が接続を受け付けると、SampleClient
およびSampleServer
により、このチュートリアルで解説した方法で、共有コンテキストの確立およびメッセージの交換が行われます。
ログイン時のトラブルシューティングは、ログインのトラブルシューティングを参照してください。
クライアントから委譲されたクレデンシャルの使用
クライアントがクレデンシャルをサーバーに委譲する場合、完成度のもっとも高い方法でクライアントを装うことができます。
コンテキスト・アクセプタ(前のチュートリアルのサーバー)とのコンテキストを確立する前に、コンテキスト・イニシエータ(クライアント)によりさまざまなコンテキスト・オプションの設定が行われたことを思い起こしてください。次に示すように、イニシエータがcontext
オブジェクトに対し、引数true
を指定してrequestCredDeleg
メソッドを呼び出す場合を考えましょう。
context.requestCredDeleg(true);
この場合、コンテキスト確立時に、イニシエータのクレデンシャルをアクセプタに委譲することが求められます。
イニシエータからアクセプタにクレデンシャルを委譲することにより、アクセプタが自らをイニシエータのエージェントまたは代理人として認証することが可能になります。
コンテキスト確立後に、アクセプタはクレデンシャルの委譲が実際に行われたかどうかを最初に確認する必要があります。これは、getCredDelegState
メソッドを呼び出すことで実行されます。
boolean delegated = context.getCredDelegState();
クレデンシャルが委譲されている場合、アクセプタはgetDelegCr
メソッドを呼び出して、そのクレデンシャルを取得できます。
GSSCredential clientCr = context.getDelegCred();
結果のGSSCredentialオブジェクトを使用して、以降のGSS-APIコンテキストをイニシエータの「委譲」として開始できます。たとえば、サーバーは、バックエンド・サーバーに対し、クライアントとして認証できます。バックエンド・サーバーには、中間的サーバーはどれかということよりも、元のクライアントがどれかということの方が重要です。
サーバーは、クライアントとして動作することにより、バックエンド・サーバーとの接続確立、結合セキュリティ・コンテキストの確立、およびメッセージ交換を、クライアントやサーバーと基本的に同じ方法で実行できます。
これを実行する1つの方法は、サーバーがGSSManagerのcreateContext
メソッドを呼び出す際に、createContext
にnull
ではなく委譲されたクレデンシャルを渡すことです。
制約付き委任
制約付き委任がKDCサーバーで構成されている場合、サーバー側では、クライアントがrequestCredDeleg(true)を呼び出さない場合でも、KDC設定に応じて、getCredDelegState()呼出しは依然としてtrueを返す可能性があり、getDelegCred()は委譲されたクレデンシャルを返します。