前のチュートリアル チュートリアルの紹介および目次 フィードバック

Java GSS-API および JAAS で実行可能な他の操作



前のチュートリアル、「JAAS Login ユーティリティおよび Java GSS-API を使用した安全なメッセージ交換」では、2 つのアプリケーション (特にクライアントとサーバ) が Java GSS-API を使用して相互間のセキュリティ保護されたコンテキストを確立して、メッセージを安全に交換する方法を示しました。

コンテキストイニシエータ (このクライアント/サーバの例ではクライアント) を使用してコンテキストを確立したあとで、コンテキストアクセプタ (サーバ) が実行可能な操作は他にもあります。基本的に、サーバはクライアントを「装う」ことができます。偽装のレベルは、クライアントが資格をサーバに委譲しているかどうかにより異なります。


クライアントユーザでのコードの実行

サーバがクライアントを装う 1 つの方法は、クライアントコードを実行するのと同じエンティティ (ユーザ) でコードを実行することです。通常、スレッドにより実行されるメソッドは、そのスレッド自体のアクセス制御設定を使用します。ただし、このチュートリアルでは、サーバがクライアントを装う際、クライアントのアクセス制御設定を使用するため、サーバはクライアント自体が実行時に保持する、厳密に同じリソースにアクセスできます。

このチュートリアルで使用する方法の主要な利点は、JAAS 承認コンポーネントをアクセス制御に使用できることです。JAAS 承認コンポーネントがない場合、サーバ主体は、クライアントユーザで実行されるコードがアクセスするすべてのリソースにアクセスできなければなりません。また、サーバコードに、ユーザがそのリソースにアクセスすることが承認されているかどうかを判別するためのアクセス制御ロジックを含める必要があります。JAAS 承認を利用することにより、主体ベースのアクセス制御が提供されるため、アクセス制御が自動的に処理されます。これらのコード内のセキュリティ関連操作のアクセス権は、ユーザにのみ付与する必要があり、サーバコードに付与する必要はありません。JAAS 承認の詳細は、「JAAS 承認」チュートリアルを参照してください。

基本的なアプローチ

サーバは、どのようにしてクライアントを「装い」、クライアントコードを実行するユーザでコードを実行できるのでしょうか。基本的に、そのユーザでクライアントコードを実行する場合と同じ方法が使用されます。すべてのサーバコードは、ユーザの主体名を認識する必要があります。ユーザの主体名は、クライアントで確立されたコンテキストから取得できます。

クライアントコードを実行するユーザの JAAS 認証により、ユーザ (主体) 名を保持する主体を含む被認証者が作成されることはすでに学びました。その後、主体は (Login ユーティリティからの Subject.doAsPrivileged 呼び出しを介して) 新しいアクセス制御コンテキストに関連付けられ、クライアントコードがそのユーザで実行されるものと見なされます。以降のアクセス制御は、必要なアクセス権がクライアントコードを実行する特定のユーザに付与されるかどうかに基づいて決定されます。

サーバコードも同様に処理されます。ただし、一般に、認証の指定された主体はユーザ主体ではなく「サービス主体」である点が異なります。再度、指定された主体名の主体を含む被認証者が作成され、Subject.doAsPrivileged が呼び出されます。サーバコードは指定された主体で実行されると見なされます。以降のアクセス制御は、必要なアクセス権がサーバコードを実行する特定の主体に付与されるかどうかに基づいて決定されます。

いったんクライアントおよびサーバが相互コンテキストを確立すると、次のコードでコンテキストイニシエータの名前 (クライアントの主体名) を確認できます。

GSSName clientGSSName = context.getSrcName();

コンテキストアクセプタ (サーバ) は、この名前を使用して、同じエンティティを表す主体を含む被認証者を生成できます。たとえば、サンの提供する JRE を使用している場合、次の方法で被認証者を生成できます。

Subject client =
com.sun.security.jgss.GSSUtil.createSubject(clientGSSName, null);

createSubject メソッドは、引数として指定された GSSName および GSSCredential から新たな被認証者を作成します。サーバコードがローカル JVM 内のユーザでコードを実行する場合、ユーザの資格は必要ではありません。実際のところ、クライアントがサーバに資格を委譲しているのでないかぎり、ユーザの資格は取得できません。詳細は、「クライアントから委譲された資格の使用」を参照してください。ここでは資格は必要ではないため、GSSCredential 引数に null を渡します。


注: Sun の提供する JRE を使用しているのではない場合、これを実行する別の方法は、次のようにして KerberosPrincipal インスタンスを生成することです。
KerberosPrincipal principal =
new KerberosPrincipal(clientGSSName.toString());

次に、この主体を使用して新たな被認証者を生成するか、既存の被認証者の主体セット内でこの主体を生成します。


サーバがユーザとして実行するコードは、java.security.PrivilegedAction (または java.security.PrivilegedExceptionAction) を実装する run メソッドで開始する必要があります。つまり、コードをこの run メソッド内に配置することも、run メソッドから呼び出すこともできます。

サーバコードは、PrivilegedAction (または PrivilegedExceptionAction) のインスタンスとともに被認証者を Subject.doAsPrivileged に渡し、以降のコードを PrivilegedAction の run メソッドから、指定された被認証者の主体 (ユーザ) で開始できます。

たとえば、PrivilegedAction クラスが ReadFileAction を呼び出し、引数として主体名を保持する String を取る場合を考えましょう。このインスタンスは、次のコードで作成できます。

String clientName = clientGSSName.toString();
PrivilegedAction readFile =
new ReadFileAction(clientName);

doAsPrivileged の呼び出しは、次のようになります。

Subject.doAsPrivileged(client, readFile, null);

サンプルコードおよびポリシーファイル

次のサンプルコードおよびポリシーファイルは、クライアントを実行する特定のユーザのみに許可されるセキュリティ関連操作用のコードを実行するために、サーバがクライアントを装う方法を示します。

SampleServerImp.java

SampleServerImp.java ファイルは、クライアントとメッセージを交換したあと、クライアントユーザとして ReadFileAction を実行するための以下のようなコードが生成される点を除けば、前のチュートリアル (「JAAS Login ユーティリティおよび Java GSS-API を使用した安全なメッセージ交換」) で紹介した SampleServer.java ファイルとまったく同じです。

System.out.println("Impersonating client.");

/*
* Extract the KerberosPrincipal from the client GSSName and
* populate it in the principal set of a new Subject.Pass in a
* null for credentials since credentials will not be needed.
 */
GSSName clientGSSName = context.getSrcName();
System.out.println("clientGSSName:" + clientGSSName);
Subject client =
com.sun.security.jgss.GSSUtil.createSubject(clientGSSName,
null);

/*
* Construct an action that will read a file meant only for the
* client
*/
String clientName = clientGSSName.toString();
PrivilegedAction readFile =
new ReadFileAction(clientName);

/*
* Invoke the action via a doAsPrivileged.This allows the
* action to be executed as the client subject, and it also
* runs that code as privileged.This means that any permission
* checking that happens beyond this point applies only to
* the code being run as the client.
*/
Subject.doAsPrivileged(client, readFile, null);

ReadFileAction.java

ReadFileAction.java ファイルには、ReadFileAction クラスが含まれます。このコンストラクタは、クライアントユーザ名の String を引数に取ります。クライアントユーザ名は、ReadFileAction が読み取りを試みるファイルのファイル名の作成に使用されます。ファイル名は、次のようになります。

./data/<name>_info.txt
ここで、<name> は対応する領域を含まないクライアントユーザ名になります。たとえば、ユーザ名全体が mjones@KRBNT-OPERATIONS.ABC.COM の場合、ファイル名は次のようになります。
./data/mjones_info.txt
注: Microsoft Windows システムの場合、スラッシュをバックスラッシュで置き換えてください。

ReadFileAction の run メソッドは、指定されたファイルを読み取り、その内容を出力します。

serverimp.policy

ReadFileAction はファイルを読み取ろうとします。この操作はセキュリティチェックの対象になります。ReadFileAction はクライアントユーザ (主体) として実行されることになっているので、ReadFileAction コード自体とクライアントである主体に対して適切なアクセス権を付与する必要があります。

ReadFileAction クラスが ReadFileAction.jar という名前の JAR ファイル内に配置され、ユーザ主体名が mjones@KRBNT-OPERATIONS.ABC.COM である場合を考えましょう。この場合、ポリシーファイル内に次のコードを記述して、アクセス権を付与します。

grant CodeBase "file:./ReadFileAction.jar"
Principal javax.security.auth.kerberos.KerberosPrincipal
"mjones@KRBNT-OPERATIONS.ABC.COM" {

permission java.io.FilePermission "data/mjones_info.txt",
"read";
};
serverimp.policy ファイルは、SampleServer コードに doAsPrivileged メソッドの呼び出しに必要なアクセス権 javax.security.auth.AuthPermission "doAsPrivileged" を付与すること、および上に示した FilePermission を付与するプレースホルダを保持することを除き、前の (「JAAS Login ユーティリティおよび Java GSS-API を使用した安全なメッセージ交換」) チュートリアルの server.policy ファイルと厳密に同一です。以下に、FilePermission を付与するプレースホルダを示します。
grant CodeBase "file:./ReadFileAction.jar"
Principal javax.security.auth.kerberos.KerberosPrincipal
"your_user_name@your_realm" {

permission java.io.FilePermission "data/your_user_name_info.txt",
"read";
};

ここで、your_realm は使用する Kerberos 領域で、your_user_name@your_realmdata/your_user_name_info.txt 内の your_user_name は使用するユーザ名で置き換える必要があります。Microsoft Windows システムの場合、data/your_user_name_info.txt 内の「/」を「\」で置き換えてください。

サンプルコードの実行

クライアントを装うサーバのサンプルコードを実行する場合、前のチュートリアルの「SampleClient および SampleServer プログラムの実行」に説明されているのと同じ操作を実行してください。ただし、以下の点が異なります。

クライアントから委譲された資格の使用

クライアントが資格をサーバに委譲する場合、完成度のもっとも高い方法でクライアントを装うことができます。

コンテキストアクセプタ (前のチュートリアルのサーバ) とのコンテキストを確立する前に、コンテキストイニシエータ (クライアント) によりさまざまなコンテキストオプションの設定が行われたことを思い起こしてください。次に示すように、イニシエータが context オブジェクトに対し、引数 true を指定して requestCredDeleg メソッドを呼び出す場合を考えましょう。

context.requestCredDeleg(true);
この場合、コンテキスト確立時に、イニシエータの資格をアクセプタに委譲することが求められます。

イニシエータからアクセプタに資格を委譲することにより、アクセプタが自らをイニシエータのエージェントまたは代理人として認証することが可能になります。

コンテキスト確立後に、アクセプタは資格の委譲が実際に行われたかどうかを最初に確認する必要があります。これは、getCredDelegState メソッドを呼び出すことで実行されます。

boolean delegated = context.getCredDelegState();

資格が委譲されている場合、アクセプタは getDelegCr メソッドを呼び出して、その資格を取得できます。

GSSCredential clientCr = context.getDelegCr();

作成された GSSCredential を使用して、以降の GSS-API コンテキストをイニシエータの「代理人」として開始することができます。たとえば、サーバは、バックエンドサーバに対し、クライアントとして認証を行います。バックエンドサーバには、中間的サーバはどれかということよりも、元のクライアントがどれかということの方が重要です。

サーバは、クライアントとして動作することにより、バックエンドサーバとの接続確立、結合セキュリティコンテキストの確立、およびメッセージ交換を、クライアントやサーバと基本的に同じ方法で実行できます。

これを実行する 1 つの方法は、サーバが GSSManager の createContext メソッドを呼び出す際に、createContextnull ではなく委譲された資格を渡すことです。

別の選択肢として、サーバコードが最初に com.sun.security.jgss.GSSUtil createSubject メソッドを呼び出し、それに委譲された資格を渡すという方法もあります。このメソッドは、これらの資格をデフォルトの資格として含む被認証者を返します。その後、「JAAS 承認」チュートリアルの「被認証者のアクセス制御コンテキストへの関連付け」で説明したように、サーバは、この被認証者を現行の AccessControlContext に関連付けることができます。次に、サーバコードは、GSSManager createContext メソッドの呼び出し時に、null (「現行の」被認証者を資格として使用することを指示する) を渡すことができます。違う言い方をすれば、サーバが実質的にクライアントになります。GSS を使用するその後のバックエンドサーバへの接続は、前のチュートリアルで説明されるとおりの方法で確立することができます。これは、委譲された資格を使用するコードが、デフォルトのローカル資格を使用するコードと同一であることが必要な場合に有用な方法です。

資格の委譲に必要なアクセス権

資格を委譲するには、コンテキストイニシエータ (前のチュートリアルでは SampleClient) が javax.security.auth.kerberos.DelegationPermission を保持する必要があります。例を次に示します (斜体のプレースホルダには実際の値を指定)。

permission javax.security.auth.kerberos.DelegationPermission
"\"service_principal@your_realm\"  
\"krbtgt/your_realm@your_realm\"";

DelegationPermission が保持する単一のターゲット内に、引用符で囲まれた 2 つの項目が含まれることに注目してください。内部の各引用符は、「\」でエスケープされています。このため、最初の項目は次のようになります。

"service_principal@your_realm"
2 番目の項目は、次のようになります。
"krbtgt/your_realm@your_realm"

これは、基本的に、クライアントとして実行されるコードに対し、指定されたピアに Kerberos チケットを転送するためのアクセス権を付与します。Kerberos チケットは、krbtgt/your_realm@your_realm からのサービス利用に使用します。

表示されている your_realm は、すべて実際の領域で置き換えてください。また、service_principal@your_realm も、サービス主体名 (サーバを表すサービス主体の名前) で置き換えてください(前のチュートリアルの「Kerberos ユーザおよびサービス主体の名前」を参照)。領域が KRBNT-OPERATIONS.ABC.COM で、サービス主体が「sample/raven.abc.com@KRBNT-OPERATIONS.ABC.COM」である場合を考えてみましょう。この場合、アクセス権をポリシーファイル内で次のように表示できます。

permission javax.security.auth.kerberos.DelegationPermission
"\"sample/raven.abc.com@KRBNT-OPERATIONS.ABC.COM\"
\"krbtgt/KRBNT-OPERATIONS.ABC.COM@KRBNT-OPERATIONS.ABC.COM\"";


前のチュートリアル チュートリアルの紹介および目次 フィードバック