3.4. サブジェクトの認証
サブジェクトの認証には JAAS ログインが必要です。ログイン手順は次のようになります。
- アプリケーションは
LoginContext
をインスタンス化し、ログイン設定の名前とCallbackHandler
を渡して、設定LoginModule
が必要とするCallback
オブジェクトを追加します。 LoginContext
は、名前付きログイン設定に含まれるすべてのLoginModules
をロードするためConfiguration
を確認します。このような名前付き設定が存在しない場合は、other
設定がデフォルトで使用されます。- アプリケーションによって、
LoginContext.login
メソッドが呼び出されます。 - ログインメソッドはロードされたすべての
LoginModule
を呼び出します。各LoginModule
はサブジェクトを認証するため、関連するLoginModule
でハンドルメソッドを呼び出し、認証プロセスに必要な情報を取得します。必要な情報は、Callback
オブジェクトのアレイの形式でハンドルメソッドに渡されます。認証に成功すると、LoginModule
は関連のプリンシパルとクレデンシャルをサブジェクトに関連付けします。 LoginContext
は認証ステータスをアプリケーションに返します。ログインメソッドから返されると認証が成功したことになります。ログインメソッドによって LoginException がスローされると認証に失敗したことになります。- 認証に成功すると、アプリケーションは
LoginContext.getSubject
メソッドを使用して認証されたサブジェクトを取得します。 - サブジェクトの認証が完了した後に
LoginContext.logout
メソッドを呼び出すと、login
メソッドによりサブジェクトに関連付けられたすべてのプリンシパルおよび関連情報を削除できます。
LoginContext
クラスは、サブジェクト認証の基本メソッドを提供し、基礎となる認証技術に依存しないアプリケーションを開発する方法を提供します。LoginContext
は、特定のアプリケーション向けに設定された認証サービスを決定するため Configuration
を確認します。LoginModule
クラスは認証サービスを表します。そのため、アプリケーション自体を変更しなくても、異なるログインモジュールをアプリケーションにプラグ可能です。次のコードは、アプリケーションがサブジェクトを認証するために必要となる手順を示しています。
CallbackHandler handler = new MyHandler(); LoginContext lc = new LoginContext("some-config", handler); try { lc.login(); Subject subject = lc.getSubject(); } catch(LoginException e) { System.out.println("authentication failed"); e.printStackTrace(); } // Perform work as authenticated Subject // ... // Scope of work complete, logout to remove authentication info try { lc.logout(); } catch(LoginException e) { System.out.println("logout failed"); e.printStackTrace(); } // A sample MyHandler class class MyHandler implements CallbackHandler { public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException { for (int i = 0; i < callbacks.length; i++) { if (callbacks[i] instanceof NameCallback) { NameCallback nc = (NameCallback)callbacks[i]; nc.setName(username); } else if (callbacks[i] instanceof PasswordCallback) { PasswordCallback pc = (PasswordCallback)callbacks[i]; pc.setPassword(password); } else { throw new UnsupportedCallbackException(callbacks[i], "Unrecognized Callback"); } } } }
開発者は、
LoginModule
インターフェースの実装を作成することで、認証技術を統合します。これにより、管理者は異なる認証技術を 1 つのアプリケーションにプラグできます。複数の LoginModule
をチェーン化し、複数の認証技術を認証プロセスに加えることが可能です。たとえば、1 つの LoginModule
がユーザー名およびパスワードベースの認証を行い、別の LoginModule
をスマートカードリーダや生体認証などのハードウェアデバイスへ接続するインターフェースとすることが可能です。
LoginModule
のライフサイクルは、クライアントがログインメソッドを作成し公開するLoginContext
オブジェクトによって決定されます。このプロセスには 2 つのフェーズがあり、プロセスの手順は次のようになります。
LoginContext
は引数のないパブリックコンストラクターを使用して、設定されたLoginModule
を作成します。- 各
LoginModule
は、初期化メソッドへの呼び出しによって初期化されます。Subject
引数は null 以外になることが保証されます。初期化メソッドのシグネチャーはpublic void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
です。 login
メソッドは、認証プロセスを開始するために呼び出されます。たとえば、あるメソッド実装はユーザーにユーザー名とパスワードの入力を求め、NIS や LDAP などのネーミングサービスに保存されたデータに対してこの情報を検証することがあります。別の実装は、スマートカードや生体認証デバイスにインターフェースとして接続したり、基礎となるオペレーティングシステムからユーザー情報を抽出したりすることがあります。各LoginModule
によるユーザーアイデンティティーの検証は、JAAS 認証のフェーズ 1 とみなされます。login
メソッドのシグネチャーはboolean login() throws LoginException
です。LoginException
は失敗を意味します。true の戻り値はメソッドが成功したことを示し、false の戻り値はログインモジュールが無視されることを示します。LoginContext
の全体的な認証が成功すると、各LoginModule
でcommit
が呼び出されます。フェーズ 1 がLoginModule
に対して成功すると、コミットメソッドはフェーズ 2 を続行し、関連するプリンシパル、パブリッククレデンシャル、プライベートクレデンシャルをサブジェクトに関連付けます。フェーズ 1 がLoginModule
に対して失敗すると、commit
はユーザー名やパスワードなどの以前保存した認証状態をすべて削除します。commit
メソッドのシグネチャーはboolean commit() throws LoginException
です。LoginException
がスローされると、コミットフェーズの完了に失敗したことを示します。true が返されるとメソッドが成功したことを示し、false が返されるとログインモジュールが無視されることを示します。LoginContext
の全体的な認証が失敗すると、各LoginModule
でabort
メソッドが呼び出されます。abort
メソッドはログインまたは初期化メソッドによって作成されたすべての認証状態を削除または破棄します。abort
メソッドのシグネチャーはboolean abort() throws LoginException
です。LoginException
がスローされるとabort
フェーズの完了に失敗したことを示します。true が返されるとメソッドが成功したことを示し、false が返されるとログインモジュールが無視されることを示します- ログイン成功後に認証状態を削除するため、アプリケーションは
LoginContext
でlogout
を呼び出します。これにより、各LoginModule
でlogout
メソッドが呼び出されます。logout
メソッドは、commit
操作中に当初サブジェクトに関連付けられていたプリンシパルとクレデンシャルを削除します。クレデンシャルは削除時に破棄されるはずです。logout
メソッドのシグネチャーはboolean logout() throws LoginException
です。LoginException
がスローされるとログアウトプロセスの完了に失敗したことを示します。true が返されるとメソッドが成功したことを示し、false が返されるとログインモジュールが無視されることを示します。
LoginModule
がユーザーと通信して認証情報を取得する必要がある場合、CallbackHandler
オブジェクトを使用します。アプリケーションは、 CallbackHandler インターフェースを実装して LoginContext
に渡し、基礎となるログインモジュールに直接認証情報を送信します。
ログインモジュールは、
CallbackHandler
を使用して、パスワードやスマートカード PIN などのユーザー入力による情報を取得したり、ステータスなどの情報をユーザーに提供したりします。アプリケーションによる CallbackHandler
の指定を可能にすることで、基礎となる LoginModule
がアプリケーションとユーザーが対話するさまざまな方法に依存しないようにします。たとえば、GUI アプリケーションの CallbackHandler
の実装は、ウィンドウを表示してユーザーの入力を求めることがあります。一方でアプリケーションサーバーなどの GUI でない環境の CallbackHandler
実装は、アプリケーションサーバー API を使用してクレデンシャル情報を取得することがあります。 CallbackHandler インターフェースには実装するメソッドが 1 つあります。
void handle(Callback[] callbacks) throws java.io.IOException, UnsupportedCallbackException;
最後に説明する認証クラスは
Callback
インターフェースです。これは複数のデフォルト実装が提供されているタグ付けインターフェースで、前述の例で使用した NameCallback
と PasswordCallback
が含まれます。LoginModule
は Callback
を使用し、認証メカニズムで必要となる情報を要求します。LoginModule
は認証のログインフェーズの間に Callback
のアレイを直接 CallbackHandler.handle
メソッドに渡します。callbackhandler
がハンドルメソッドに渡された Callback
オブジェクトの使用方法が分からない場合は、UnsupportedCallbackException
をスローしてログイン呼び出しを中止します。