Java認証・承認サービス(JAAS)リファレンス・ガイド
ユーザーの認証にJAASを使用し、現在Javaコードを実行しているユーザーを確実かつ安全に特定できます。
JAASは、Javaバージョンの標準Pluggable Authentication Module (PAM)フレームワークを実装します。
JAAS認証は、プラガブルな方式で実行されます。これにより、アプリケーションは、基盤となる認証技術から独立した状態になります。アプリケーション自体に変更を加える必要なく、アプリケーションに新規または更新された認証技術をプラグインできます。アプリケーションは、LoginContextオブジェクトをインスタンス化することにより、認証プロセスを有効にし、LoginContextオブジェクトはConfigurationを参照して、認証の実行で使用する認証テクノロジまたはLoginModuleを判別します。一般的なLoginModuleは、ユーザー名およびパスワードの入力を求め、検証します。音声や指紋標本を読み取り、検証できるものもあります。
コードを実行するユーザーまたはサービスは、認証後にSubjectオブジェクトによって表されます。認証が成功した場合、LoginModuleは、関連するPrincipalおよび資格証明を使用してSubjectを更新します。アプリケーションまたはライブラリは、Subjectに格納されている資格証明を使用して、後続の認可を決定できます。
このドキュメントの対象読者
このドキュメントは、Subjectベースのセキュリティ・モデルの制約を受けるアプリケーションを設計する必要がある上級開発者を対象としています。また、LoginModule開発者(認証技術を実装する開発者)が、「Java Authentication and Authorization Service (JAAS): LoginModule開発者ガイド」を読む前に、このドキュメントを読むことを想定しています。
最初に「JAAS認証チュートリアル」でJAASの使用方法の概要と有効なサンプル・コードを確認し、その後でこのドキュメントに戻って詳細情報を得ることをお薦めします。
関連ドキュメント
「JAASログイン・モジュール開発者ガイド」は、認証技術を実装するLoginModuleを記述する必要がある上級プログラマ向けのドキュメントであり、このドキュメントの補足として役立ちます。
「JAAS認証チュートリアル」は、すべてのユーザーが実行できます。
「JAAS認証」は、Kerberos LoginModuleの使用方法を示す同様のチュートリアルです。Kerberosインストールが必要です。これは、認証とセキュアな通信のための基盤技術としてKerberosを利用する「JAASおよびJava GSS-APIチュートリアルの紹介」に含まれています。
コア・クラスとインタフェース
JAAS関連コア・クラスおよびインタフェースは、共通クラスと認証クラスの2つのカテゴリに分類できます。
トピック
共通クラス
共通クラスは、JAAS認証および承認コンポーネントの両方に共通です。
JAASの主要クラスは、javax.security.auth.Subjectであり、これは、単一エンティティ(個人など)の関連情報のグループ化を表します。これには、エンティティのPrincipal、publicクレデンシャルおよびprivateクレデンシャルなどがあります。
プリンシパルの表現には、java.security.Principalインタフェースが使用されます。また、JAASにより定義されるクレデンシャルには、任意のオブジェクトを指定できます。
サブジェクト
リソースへのアクセスを承認する場合、最初に、アプリケーションが要求元を認証する必要があります。JAASフレームワークでは、要求元をサブジェクトという用語で表します。サブジェクトは、個人やサービスなどの任意のエンティティです。サブジェクトが認証されると、javax.security.auth.Subjectには関連する識別情報またはプリンシパルが割り当てられます。Subjectには、多数のPrincipalを含めることができます。たとえば、ある個人は、名前Principal (「John Doe」)およびSSN Principal (「123-45-6789」)などを持ち、これらにより、他のサブジェクトと区別されます。
Subjectは、クレデンシャルと呼ばれるセキュリティ関連の属性も保持できます(クレデンシャルの項を参照)。非公開暗号化キーなどの特別な保護が必要な機密の資格は、非公開資格Set内に格納されます。公開キー証明書などの共有されるクレデンシャルは、公開クレデンシャルSet内に格納されます。
サブジェクトは、次のコンストラクタを使用して作成されます。
public Subject();
public Subject(boolean readOnly, Set principals,
Set pubCredentials, Set privCredentials);最初のコンストラクタは、Principalおよびクレデンシャルの空(nullではない)のSetでSubjectを作成します。2番目のコンストラクタは、指定されたPrincipalおよびクレデンシャルのSetでSubjectを作成します。Subjectを読取り専用にするために使用できるboolean型の引数も持っています。読取り専用のSubject内では、PrincipalおよびクレデンシャルSetは不変です。
アプリケーション作成者がSubjectをインスタンス化する必要はありません。アプリケーションがLoginContextをインスタンス化し、SubjectをLoginContextコンストラクタに渡さない場合、LoginContextは新しい空のSubjectをインスタンス化します。LoginContextの項を参照してください。
Subjectが読取り専用の状態でインスタンス化されなかった場合、次のメソッドを呼び出して読取り専用に設定できます。
public void setReadOnly();読取り専用の状態に設定したあとで、Principalやクレデンシャルを追加または削除しようとすると、IllegalStateExceptionがスローされます。次のメソッドを使用して、Subjectの読取り専用状態をテストできます:
public boolean isReadOnly();Subjectに関連したPrincipalを取得する場合、次の2つのメソッドを利用できます。
public Set getPrincipals();
public Set getPrincipals(Class c);最初のメソッドは、Subjectに含まれるすべてのPrincipalを返します。一方、2番目のメソッドは、指定されたクラスcのインスタンスまたはクラスcのサブクラスのインスタンスになっているPrincipalしか返しません。Subjectに関連付けられているPrincipalがない場合は、空のセットが返されます。
Subjectに関連した公開クレデンシャルを取得する場合は、次のメソッドを利用できます。
public Set getPublicCredentials();
public Set getPublicCredentials(Class c);これらのメソッドの動作はgetPrincipalsメソッドの動作と似ています。ただし、getPrincipalsメソッドでは、公開クレデンシャルを取得することはできません。
Subjectに関連した非公開クレデンシャルにアクセスする場合は、次のメソッドを利用できます。
public Set getPrivateCredentials();
public Set getPrivateCredentials(Class c);これらのメソッドの動作は、getPrincipalsメソッドやgetPublicCredentialsメソッドとよく似ています。
SubjectのPrincipal Set、公開クレデンシャルSet、または非公開クレデンシャルSetを変更または操作する場合、呼出し側はjava.util.Setクラスで定義されたメソッドを使用します。その方法を示すサンプル・コードを次に示します。
Subject subject;
Principal principal;
Object credential;
// ...
// add a Principal and credential to the Subject
subject.getPrincipals().add(principal);
subject.getPublicCredentials().add(credential);ノート:
引数なしのgetPrincipals()、getPublicCredentials()、getPrivateCredentials()メソッドを介して返されるセットのみが、Subjectの対応する内部セットによってサポートされます。このため、返されたセットを変更すると、内部セットも影響を受けます。getPrincipals(Class c)、getPublicCredentials(Class c)およびgetPrivateCredentials(Class c)メソッドを介して返されるセットは、Subjectの対応する内部セットによってサポートされません。メソッド呼び出しごとに、新規セットが作成され、返されます。これらのセットを変更しても、Subjectの内部セットに影響はありません。
次のメソッドでは、指定したSubjectとしてアクションを実行できます:
public static <T> T callAs(Subject subject, Callable<T> action)callAsメソッドを使用してアクションを実行すると、Subjectは実行期間にバインドされます。次のメソッドは、現在のスレッドの実行期間に関連付けられたSubjectを返し、Subjectが設定されていない場合はnullを返します:
public static Subject current();詳細は、特定のSubjectとしてアクションを実行するためのcallAsおよび現在のメソッドを参照してください。
Subjectクラスには、java.lang.Objectから継承した次のメソッドも含まれます。
public boolean equals(Object o);
public String toString();
public int hashCode();特定のSubjectとしてアクションを実行するためのcallAsおよび現在のメソッド
次の静的メソッドを呼び出して、特定のSubjectとしてアクションを実行します:
public static <T> T callAs(Subject subject, Callable<T> action)
throws CompletionException「JAAS認証チュートリアル」のSampleAcn.javaの例は、次のようにSubject.callAs(Subject, Callable<T>)をコールします:
Subject.callAs(mySubject, anotherAction);この例では、引数anotherActionは、メソッドSubject.current()を使用してSubject mySubjectにアクセスします:
Callable<Void> anotherAction = () -> {
// Retrieve the current subject
Subject s = Subject.current();
System.out.println("\nCurrent subject: " + s);
// Add a new Principal to the current subject
Random r = new Random();
String pn = Integer.toString(r.nextInt());
Principal p = new sample.principal.SamplePrincipal(pn);
System.out.println("\nAdding principal " + pn);
s.getPrincipals().add(p);
// List the current subject's Principals
System.out.println("\nAuthenticated user has the following Principals:");
Iterator pi = s.getPrincipals().iterator();
while (pi.hasNext()) {
Principal nextp = (Principal)pi.next();
System.out.println("\t" + nextp.toString());
}
return null;
}; 子スレッドが構造化並行性を使用して親のスレッドの実行内で起動および終了した場合、子スレッドはSubject.current()メソッドを使用して親スレッドの現在のSubjectにアクセスできます。次の例は、SampleAcn.javaからのものです:
Callable<Void> addRandomPrincipal = () -> {
Subject s = Subject.current();
// Add a new Principal
Random r = new Random();
String pn = Integer.toString(r.nextInt());
Principal p = new sample.principal.SamplePrincipal(pn);
System.out.println("\nAdding principal " + pn);
s.getPrincipals().add(p);
return null;
};
Callable<Void> structuredAction = () -> {
try (var scope = new StructuredTaskScope<>()) {
scope.fork(addRandomPrincipal);
scope.fork(addRandomPrincipal);
scope.fork(addRandomPrincipal);
scope.join();
Subject s = Subject.current();
System.out.println("\nCurrent subject: " + s);
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
};
Subject.callAs(mySubject, structuredAction);メソッドStructuredTaskScope.fork(Callable)は、タスク・スコープscopeで新しいスレッドを起動します。このメソッドは、StructuredTaskScope.Subtaskまたは分岐サブタスクを返します。この例では、3つの分岐サブタスクを作成します。各サブタスクは、Subject.current()メソッドを使用して親スレッドの現在のSubjectを取得し、新しいプリンシパルをSubjectに追加します。メソッドStructuredTaskScope.join()は、scopeのサブタスクが終了するのを待ってから続行します。次に、Subjectを出力します。この例では、3つの追加プリンシパルが含まれています。
この例の出力を表示するには、「JAAS認証チュートリアル・コードの実行」を参照してください。
ノート:
クラスStructuredTaskScopeは、プレビュー機能である構造化並行性APIの一部です。プレビュー機能は、設計、仕様および実装が完了したが、永続的でない機能です。プレビュー機能は、将来のJava SEリリースで、異なる形式で存在することもあれば、まったく存在しないこともあります。プレビュー機能が含まれているコードをコンパイルして実行するには、--enable-preview -source 24などの追加のコマンドライン・オプションを指定する必要があります。『Java Platform, Standard Edition Java言語更新』の言語およびVM機能のプレビューおよび『Java Platform, Standard Editionコア・ライブラリ』の構造化並行性に関する項を参照してください。
プリンシパル
前述したように、サブジェクトが認証されると、関連する識別情報またはプリンシパルがサブジェクトに割り当てられます。サブジェクトには、多数のプリンシパルを含めることができます。たとえば、ユーザーは、他のサブジェクトと明確に区別される名前プリンシパル(「John Doe」)およびSSNプリンシパル(「123-45-6789」)を保持できます。プリンシパルはjava.security.Principalおよびjava.io.Serializableインタフェースを実装する必要があります。サブジェクトに関連付けられたプリンシパルの更新方法の詳細は、サブジェクトを参照してください。
クレデンシャル
サブジェクトは、関連付けられたプリンシパルに加え、クレデンシャルと呼ばれる独自のセキュリティ関連属性を保持できます。クレデンシャルには、新規サービスに対してサブジェクトを認証する際に使用可能な情報が含まれます。この種のクレデンシャルには、パスワード、Kerberosチケット、および公開キー証明書が含まれます。クレデンシャルには、サブジェクトによる特定操作の実行を可能にするだけのデータが含まれる場合もあります。たとえば、暗号化キーは、サブジェクトによるデータへの署名または暗号化を可能にするクレデンシャルを表します。公開および非公開クレデンシャル・クラスは、コアJAASクラス・ライブラリの一部ではありません。したがって、あらゆるクラスがクレデンシャルを表すことができます。
公開および非公開クレデンシャル・クラスは、コアJAASクラス・ライブラリの一部ではありません。ただし、開発者は、クレデンシャルに関連する2つのインタフェース、RefreshableおよびDestroyableを実装するクレデンシャル・クラスを持つことを決定できます。
トピック
Refreshable
このjavax.security.auth.Refreshable インタフェースは、クレデンシャルの自動リフレッシュ機能を提供します。たとえば、有効期間の制限された資格がこのインタフェースを実装すると、呼出し側が有効期間を更新できるようになります。このインタフェースには、次の2つのabstractメソッドがあります。
- boolean isCurrent(): 資格証明が現在有効かどうかを判別します
- void refresh() throws RefreshFailedException: 資格証明の妥当性を更新または拡張します
Destroyable
このjavax.security.auth.Destroyable インタフェースは、クレデンシャル内のコンテンツを破棄する機能を提供します。このインタフェースには、次の2つのabstractメソッドがあります。
- boolean isDestroyed(): 資格証明が破棄されたかどうかを判別します
- void destroy() throws DestroyFailedException: この資格証明に関連する情報を破棄およびクリアします
認証クラスとインタフェース
認証は、サブジェクトの識別情報を検証するプロセスを表し、セキュアな方法で実行する必要があります。さもないと、悪意のあるユーザーが他のユーザーを装ってシステムへのアクセスを試みる可能性があります。通常、認証には、識別情報を証明するなんらかの形式の証拠を示すサブジェクトが含まれます。この種の証拠には、サブジェクトのみが知るか保持できる情報(パスワードや指紋など)またはサブジェクトのみが作成可能な情報(秘密キーを使用した署名付きデータなど)があります。
サブジェクト(ユーザーまたはサービス)の認証では、次のステップが行われます。
- アプリケーションが
LoginContextをインスタンス化します。 LoginContextが、Configurationに問い合わせを行い、アプリケーション用に構成されたすべてのLoginModuleをロードします。- アプリケーションが、
LoginContextのloginメソッドを呼び出します。 loginメソッドがロードされたすべてのLoginModuleを呼び出します。各LoginModuleはサブジェクトを認証しようとします。成功した場合、LoginModuleは、認証されるサブジェクトを表すSubjectオブジェクトに、適切なPrincipalとクレデンシャルを関連付けます。LoginContextが、認証ステータスをアプリケーションに返します。- 認証が成功すると、アプリケーションは
SubjectをLoginContextから取得します。
次の項では、認証クラスについて説明します。
LoginContext
javax.security.auth.login.LoginContextクラスは、サブジェクトの認証に使用する基本的なメソッドを提供し、基盤となる認証テクノロジから独立したアプリケーションを開発する方法を提供します。LoginContextは、Configurationを調べて、特定のアプリケーション用に構成された認証サービスまたはLoginModuleを判別します。このため、アプリケーション自体に変更を加えることなく、アプリケーションに様々なLoginModuleをプラグインできます。
LoginContextは、選択可能な次の4つのコンストラクタを提供します。
public LoginContext(String name) throws LoginException
public LoginContext(String name, Subject subject) throws LoginException
public LoginContext(String name, CallbackHandler callbackHandler)
throws LoginException
public LoginContext(String name, Subject subject,
CallbackHandler callbackHandler) throws LoginExceptionすべてのコンストラクタは、共通のパラメータnameを共有します。LoginContextは、この引数をログインConfigurationのインデックスとして使用し、LoginContextのインスタンス化を行うアプリケーション用として構成されるLoginModuleを特定します。Subjectを入力パラメータとして取らないコンストラクタは、新規Subjectをインスタンス化します。どのコンストラクタでも、nullの入力は許可されません。
CallbackHandlerとこれが必要な状況の詳細は、CallbackHandlerを参照してください。
実際の認証は、次のメソッドへの呼出しを使って行われます。
public void login() throws LoginExceptionloginを呼び出すと、すべての構成済みLoginModuleが呼び出され、認証を実行します。認証に成功した場合は、次のメソッドを使用して、認証されたSubject (Principal、公開クレデンシャル、非公開クレデンシャルを保持している場合がある)を取得できます。
public Subject getSubject()Subjectをログアウトして、認証済みのPrincipalsおよびクレデンシャルを削除するには、次のメソッドを使用します。
public void logout() throws LoginException次のサンプル・コードは、Subjectの認証およびログアウトに必要なコールを示します:
// let the LoginContext instantiate a new Subject
LoginContext lc = new LoginContext("entryFoo");
try {
// authenticate the Subject
lc.login();
System.out.println("authentication successful");
// get the authenticated Subject
Subject subject = lc.getSubject();
// ...
// all finished -- logout
lc.logout();
} catch (LoginException le) {
System.err.println("authentication unsuccessful: " +
le.getMessage());
}LoginModule
LoginModule インタフェースを使用すると、異なる種類の認証技術を実装して、アプリケーションでプラグインとして利用できます。たとえば、ユーザー名/パスワードベースの認証を実行できるLoginModuleがあります。スマート・カードやバイオメトリック・デバイスなどのハードウェアへのインタフェースを提供するLoginModuleもあります。
ノート:
アプリケーション作成者は、LoginModuleの機能を理解している必要はありません。アプリケーションを作成し、構成情報(ログイン構成ファイルの情報など)を指定し、アプリケーションが構成によって指定されたログイン・モジュールを利用してユーザーを認証できるようにするだけで十分です。
一方、認証技術を実装するLoginModuleを作成する必要があるプログラマは、Java Authentication and Authorization Service (JAAS): LoginModule開発者ガイドで具体的なステップを確認してください。
CallbackHandler
LoginModuleがユーザーと通信して、認証情報を取得する必要がある場合があります。LoginModuleは、この目的でjavax.security.auth.callback.CallbackHandlerを使用します。アプリケーションはCallbackHandlerインタフェースを実装し、それをLoginContextに転送します。LoginContextは、それを基礎となるLoginModuleに直接転送します。LoginModuleはCallbackHandlerを使用して、ユーザーからの入力(パスワードやスマート・カードの暗証番号など)を収集したり、ユーザーに情報(ステータス情報など)を提供したりします。アプリケーションにCallbackHandlerの指定を許可することにより、基礎となるLoginModulesは、アプリケーションとユーザー間の通信方法から独立した状態にすることができます。たとえば、GUIアプリケーション用のCallbackHandlerの実装は、ウィンドウを表示してユーザーの入力を求めることができます。一方、非GUIツール用のCallbackHandlerの実装では、単にユーザーにコマンドラインから直接入力するように求めることができます。CallbackHandlerは、実装する1つのメソッドを持つインタフェースです:
void handle(Callback[] callbacks)
throws java.io.IOException, UnsupportedCallbackException;
LoginModuleはCallbackHandler handleメソッドに適切なCallback (ユーザー名に対してはNameCallback、パスワードに対してはPasswordCallback)で構成される配列を渡し、CallbackHandlerは要求に従ってユーザーと通信し、Callback内に適切な値を設定します。たとえば、NameCallbackを処理する場合、CallbackHandlerはユーザーから名前を取得し、NameCallbackのsetNameメソッドを呼び出してその名前を格納します。
CallbackHandlerのドキュメントには、このドキュメントには記載されていない大量のサンプルが記載されています。
コールバック
javax.security.auth.callbackパッケージには、コールバック・インタフェースおよびいくつかの実装が含まれています。LoginModulesは、コールバックの配列を、CallbackHandlerのhandleメソッドに直接渡すことができます。
使用方法の詳細については、各種Callback APIを参照してください。
JAAS認可
JDK 24でセキュリティ・マネージャが永続的に無効化される前は、JAAS認可コンポーネントによって、ユーザーが実行するアクションに必要なアクセス制御権限(または権限)を持っているかが確認されていました。コードを実行するユーザーまたはサービスが認証されると、JAAS認可コンポーネントはコアJava SEアクセス制御モデルおよびセキュリティ・マネージャと連携して、機密リソースへのアクセスを保護していました。
セキュリティ・マネージャが永続的に無効化されて、この認可メカニズムが依存するポリシー・ファイルと権限が削除または無効化されたため、この認可メカニズムは、サポートされなくなりました。そのため、認可はアプリケーション・コードが行う必要があります。これは、認証後にSubject内に格納されるプリンシパルおよび資格証明に基づくことができます。
たとえば、「JAAS認証チュートリアル」で説明されている例を考えてみます。LoginModuleインタフェースを実装するSampleLoginModule.javaクラスは、パスワードを使用してユーザーを認証します。ユーザーを認証した後、Subjectから情報(プリンシパルや資格証明など)を抽出して、後続の認可決定に使用できます。SampleAcn.javaクラスは、Subject.callAsメソッドを使用して、認証されたSubjectでCallable anotherActionを実行します:
Subject.callAs(mySubject, anotherAction);現在のSubjectにプリンシパルが1つあるとします。次の例では、このプリンシパルを取得し、プリンシパルのアイデンティティに基づいてアクセス権を付与するSampleAcn.javaからの抜粋にコードを追加します:
Callable<Void> anotherAction = () -> {
Subject s = Subject.current();
System.out.println("\nCurrent subject: " + s);
Optional<Principal> principal = s.getPrincipals().stream().findFirst();
// Authorize principal
if (principal.isPresent() &&
principal.get().getName().equals("Duke")) {
// Grant access (code not shown)
// ...
}
}付録A: java.securityセキュリティ・プロパティ・ファイルでのJAAS設定
java.securityマスター・セキュリティ・プロパティ・ファイル内で多数のJAAS関連設定を構成できます。このファイルは、JDKのconf/securityディレクトリ内にあります。
JAASは、java.securityに次の2つの新しいセキュリティ・プロパティを追加します。
login.configuration.providerlogin.config.url.n
次に、これらのプロパティを構成する方法の例を示します。この例では、login.configuration.providerセキュリティ・プロパティのデフォルトのjava.securityファイル内の値はそのまま使用します。デフォルトのjava.securityファイルでは、login.config.url.nセキュリティ・プロパティの値も一覧表示されていますがコメント化されています。次の例ではコメント化されていません。
#
# Class to instantiate as the javax.security.auth.login.Configuration
# provider.
#
login.configuration.provider=sun.security.provider.ConfigFile
#
# Default login configuration file
#
login.config.url.1=file:${user.home}/.java.login.configノート:
このファイルへの変更は、後続のJDK更新によって上書きされることがあります。ただし、システム・プロパティjava.security.properties=<URL>を使用して、代替のjava.securityプロパティ・ファイルをコマンド行から指定できます。このプロパティ・ファイルはシステム・プロパティ・ファイルの末尾に追加されます。両方のプロパティ・ファイルが同じキーに対する値を指定している場合、コマンド行プロパティ・ファイルが最後にロードされるため、このファイルの値が選択されます。
また、java.security.properties==<URL>と指定すると(2つの等号を使用)、プロパティ・ファイルはシステム・プロパティ・ファイルを完全にオーバーライドします。
追加のプロパティ・ファイルをコマンド行から指定するための機能を無効にするには、システム・プロパティ・ファイル内のキーsecurity.overridePropertiesFileをfalseに設定します。これはデフォルトではtrueに設定されています。
トピック
ログイン構成プロバイダ
Oracleが提供するデフォルトのJAASログイン構成実装は、その構成情報をファイルから取得します。この情報は、チュートリアルに記載されている特殊な形式で提供されることになっています。
代替プロバイダ・クラス実装をlogin.configuration.providerプロパティ内に指定することで、デフォルトのJAASログイン構成実装を置き換えることができます。
たとえば:
login.configuration.provider=com.foo.Config
セキュリティ・プロパティlogin.configuration.providerが見つからない、または指定されていない場合、デフォルト値が設定されます。
login.configuration.provider=com.sun.security.auth.login.ConfigFile
ログイン構成プロバイダを、コマンド行から動的に設定することはできません。
ログイン構成URL
Oracleが提供するデフォルト実装のように、ファイル内に構成情報が指定されていることを期待するログイン構成実装を使用している場合は、login.config.url.nプロパティに個々のURLを指定することにより、ログイン構成ファイルの位置を静的に設定できます。nは、1から始まる連続した番号の整数です。複数の構成ファイルが指定されている場合(n >= 2の場合)、それらは読み込まれ、結合されて単一の構成になります。
たとえば:
login.config.url.1=file:C:/config/.java.login.config
login.config.url.2=file:C:/users/foo/.foo.login.config
構成ファイルの位置がjava.securityプロパティ・ファイルに指定されておらず、コマンド行から-Djava.security.auth.login.configオプションを使って動的に指定されてもいない場合、JAASは次からデフォルト構成のロードを試みます。
file:${user.home}/.java.login.config
付録B: JAASログイン構成ファイル
JAAS認証はプラガブルな形式で実行されるため、Javaアプリケーションは、基盤となる認証技術から独立した状態を維持できます。適切な認証技術などの構成情報は実行時に指定されます。構成情報のソース(ファイルやデータベース)は、現在のjavax.security.auth.login.Configuration実装によって異なります。デフォルトのConfiguration実装ConfigFileは、その構成情報をログイン構成ファイルから取得します。JAASの提供するデフォルト・ログインConfiguration実装の詳細は、com.sun.security.auth.login.ConfigFileクラスを参照してください。
ログイン構成ファイルの構造および内容
ログイン構成ファイルは、1つ以上のエントリで構成され、各エントリには、特定のアプリケーションで使用される基礎となる認証技術が指定されます。各エントリの構造を、次に示します。
<name used by application to refer to this entry> {
<LoginModule> <flag> <LoginModule options>;
<optional additional LoginModules, flags and options>;
};
このため、各ログイン構成ファイルのエントリは、名前、続いて1つ以上のLoginModule固有エントリから構成され、LoginModule固有の各エントリはセミコロンで終わり、LoginModule固有エントリ・グループ全体が中カッコで囲まれます。各構成ファイルのエントリはセミコロンで終わります。
例6-1 JAAS認証チュートリアルのログイン構成ファイル
たとえば、JAAS認証チュートリアルのチュートリアルで使用するログイン構成ファイルには、次のエントリのみが含まれます
Sample {
sample.module.SampleLoginModule required debug=true;
};
ここでは、エントリの名前はSampleで、JAAS認証チュートリアル・アプリケーション(SampleAcn.java)がこのエントリを参照するために使用する名前です。このエントリは、ユーザー認証の実行に使用するLoginModuleがsample.moduleパッケージ内のSampleLoginModuleであること、および認証が成功したと見なされるためにはこのSampleLoginModuleが「成功する」必要があることを示します。SampleLoginModuleは、ユーザーから提供された名前とパスワードが期待したもの(それぞれtestUserとtestPassword)である場合にかぎり成功します。
JAAS認証チュートリアルのJAAS認証チュートリアルで説明したように、ログイン構成ファイルのエントリの名前は、LoginContextのインスタンス化時にアプリケーションがエントリの参照に使用する名前です。アプリケーション開発者は、任意の名前を設定できます。ここで、「アプリケーション」とは、JAASログインを実行するあらゆるコードを指します。
指定したLoginModulesは、認証プロセスの制御に使用されます。認証は、Configurationクラスで説明するように、リスト内を指定された正確な順番で下に進みます。
各LoginModule固有のエントリ・サブパートを、次に示します。
-
LoginModule: これは、目的の認証技術を実装するクラスを指定します。特に、このクラスは、
javax.security.auth.spiパッケージに含まれるLoginModuleクラスのサブクラスでなければなりません。通常、LoginModuleは、これらのチュートリアルで使用するSampleLoginModule(sample.moduleパッケージ内)と同じように、ユーザー名とパスワードを要求し、検証します。どのベンダーの提供するログイン・モジュール実装でも使用可能です。いくつかの実装が、OracleのJDKに同梱されています。様々なLoginModuleのリファレンス・ドキュメントを参照できます。すべて、com.sun.security.authパッケージ内にあります。 -
フラグ: フラグ値は、前のLoginModuleの成功が
required、requisite、sufficientまたはoptionalであるかを示します。チュートリアルのように、存在するLoginModule固有のエントリが1つだけの場合、フラグを「required」にする必要があります。オプションは、Configurationクラスで詳しく説明しています。 -
LoginModuleオプション: 指定されたLoginModule実装でオプションの設定が可能な場合、ここで任意のオプション値を指定できます。空白で区切られた値リストは、基盤となるLoginModuleに直接渡されます。各オプションはLoginModule自身によって定義されており、内部の動作を制御します。たとえば、LoginModuleでデバッグ/テスト機能をサポートするオプションを定義する場合を考えましょう。
構成ファイルのオプションを指定する適正な方法は、名前-値ペアの使用です(たとえば
debug=true)。オプション名(この場合はdebug)と値(この場合はtrue)は、等号で区切ります。
例6-2 required、sufficient、requisiteおよびoptionalのフラグを説明するログイン構成ファイル
次は、required、sufficient、requisiteおよびoptionalフラグを示すサンプル・ログイン構成ファイルです。これらのフラグの詳細は、Configurationクラスを参照してください。
Login1 {
sample.SampleLoginModule required debug=true;
};
Login2 {
sample.SampleLoginModule required;
com.sun.security.auth.module.NTLoginModule sufficient;
com.foo.SmartCard requisite debug=true;
com.foo.Kerberos optional debug=true;
};アプリケーションLogin1は、構成済のLoginModuleの、SampleLoginModuleのみを保持します。このため、Login1がサブジェクト(ユーザーまたはサービス)を認証しようとする試みは、SampleLoginModuleが成功した場合にのみ成功します。
アプリケーションLogin2の認証ロジックは、次の表で簡単に説明できます。
表6-1 Login2の認証ステータス
| モジュール・クラス | フラグ | 認証の試行1 | 認証の試行2 | 認証の試行3 | 認証の試行4 | 認証の試行5 | 認証の試行6 | 認証の試行7 | 認証の試行8 |
|---|---|---|---|---|---|---|---|---|---|
|
|
required |
pass |
pass |
pass |
pass |
fail |
fail |
fail |
fail |
|
|
sufficient |
pass |
fail |
fail |
fail |
pass |
fail |
fail |
fail |
|
SmartCard |
requisite |
* |
pass |
pass |
fail |
* |
pass |
pass |
fail |
|
Kerberos |
オプション |
* |
pass |
fail |
* |
* |
pass |
fail |
* |
|
全体の認証 |
該当なし |
pass |
pass |
pass |
fail |
fail |
fail |
fail |
fail |
*=前のrequisiteモジュールが失敗するか、または前のsufficientモジュールが成功したため、アプリケーションに制御が返されるので、この値は微妙に変化します。
使用するログイン構成ファイルの位置指定
使用する構成ファイルは、次の2つのいずれかの方法で指定できます。
-
コマンド行。
-Djava.security.auth.login.configインタプリタ・コマンド行引数を使用して、使用すべきログイン構成ファイルを指定できます。この方法は、すべてのチュートリアルで使用されます。たとえば、JAAS認証チュートリアルでは、SampleAcnアプリケーションの実行に次のコマンドを使用します。このコマンドは、構成ファイルが現在のディレクトリのsample_jaas.configファイルであることを指定します。java -Djava.security.auth.login.config==sample_jaas.config sample.SampleAcnノート:
java.security.auth.login.configシステム・プロパティで、(等号を2つ(==)ではなく)等号を1つ(=)使用している場合、このシステム・プロパティおよびjava.securityファイルの両方で指定された構成が使用されます。 -
Javaセキュリティのプロパティ・ファイル。
ログイン構成ファイルの位置を指定する別の方法は、セキュリティ・プロパティ・ファイルの
login.config.url.nプロパティ値にURLを指定することです。セキュリティ・プロパティ・ファイルは、JDKのconf/securityディレクトリ内のjava.securityファイルです。ここで、
nは1から始まる連番の整数です。このため、必要に応じて複数のログイン構成ファイルを指定できます。この場合、login.config.url.1プロパティに最初のファイルのURLを、login.config.url.2プロパティに2番目のファイルのURLというように設定します。複数のログイン構成ファイルを指定する(つまり、n> 1の場合)、ファイルは読み取られて1つの構成に連結されます。ここで、このチュートリアルで使用する
sample_jaas.configログイン構成ファイルを指定するために、セキュリティ・プロパティ・ファイルに追加する必要のある項目の例を示します。この例は、ファイルが次のWindowsのC:\AcnTestディレクトリにあると仮定しています。login.config.url.1=file:C:/AcnTest/sample_jaas.configURLには、ユーザーの実行するオペレーティング・システムに関係なく、常にスラッシュを使用します。