18.3.2. カスタムモジュール
AuthenticationManager
は、Subject
プリンシパルの特定の使用パターンを必要とします。AuthenticationManager
と動作するログインモジュールを作成するには、JAAS Subject クラスの情報ストレージ機能と、これらの機能の想定される使用方法を完全に理解する必要があります。
LoginModule
実装を紹介します。
サブジェクト
に関連付けられたセキュリティー情報を取得できます。
java.util.Set getPrincipals() java.util.Set getPrincipals(java.lang.Class c) java.util.Set getPrivateCredentials() java.util.Set getPrivateCredentials(java.lang.Class c) java.util.Set getPublicCredentials() java.util.Set getPublicCredentials(java.lang.Class c)
サブジェクト
ID とロールについては、EAP が最も論理的な選択肢を選択しました 。getPrincipals ()
および getPrincipals (java.lang.Class)
を介して取得されたプリンシパルセットです。使用パターンは次のとおりです。
- ユーザー ID(たとえば、ユーザー名、社会保障番号、従業員 ID) は、
サブジェクト
プリンシパル
セットにjava.security.Principal
オブジェクトとして格納されます。ユーザー ID を表すプリンシパル
の実装は、プリンシパルの名前に基づいて比較と同等性を確立する必要があります。適切な実装は、org.jboss.security.SimplePrincipal
クラスとして利用できます。他のプリンシパル
インスタンスは、必要に応じてサブジェクト
プリンシパル
セットに追加できます。 - 割り当てられたユーザーロールも
プリンシパル
セットに保存され、java.security.acl.Group
インスタンスを使用して名前付きロールセットにグループ化されます。Group
インターフェイスは、Principal
および/またはGroup
のコレクションを定義し、java.security.Principal
のサブインターフェイスです。 サブジェクト
には、任意の数のロールセットを割り当てることができます。
- EAP セキュリティーフレームワークは、
Roles
とCallerPrincipal
という名前の 2 つのよく知られたロールセットを使用します。ロール
グループは、サブジェクト
が認証されたアプリケーションドメインで知られている名前付きロールのプリンシパル
のコレクションです。このロールセットは、EJBContext.isCallerInRole (String)
などのメソッドによって使用されます。EJB は、このメソッドを使用して、現在の呼び出し元が指定されたアプリケーションドメインロールに属しているかどうかを確認できます。メソッド権限チェックを実行するセキュリティーインターセプタロジックも、このロールセットを使用します。CallerPrincipal
グループ
は、アプリケーションドメインのユーザーに割り当てられた単一のプリンシパル
ID で設定されます。EJBContext.getCallerPrincipal ()
メソッドは、CallerPrincipal
を使用して、アプリケーションドメインが操作環境 ID からアプリケーションに適したユーザー ID にマップできるようにします。サブジェクト
にCallerPrincipalGroup
がない場合
、アプリケーション ID は運用環境 ID と同じです。
18.3.2.1. サブジェクト使用パターンのサポート
サブジェクト
の使用パターンの正しい実装を簡素化するため「カスタムモジュール」、EAP には、認証された サブジェクト
に正しい サブジェクト
の使用を強制するテンプレートパターンを入力するログインモジュールが含まれています。
AbstractServerLoginModule
2 つの中で最も一般的なのは、org.jboss.security.auth.spi.AbstractServerLoginModule
クラスです。
javax.security.auth.spi.LoginModule
インターフェイスの実装を提供し、運用環境のセキュリティーインフラストラクチャーに固有の主要なタスクのための抽象的なメソッドを提供します。クラスの重要な詳細は、例18.24「AbstractServerLoginModule クラスの一部」。JavaDoc コメントは、サブクラスの責任について詳しく説明しています。
loginOk
インスタンス変数は極めて重要です。ログインが成功した場合は true
に設定する必要があり、ログインメソッドをオーバーライドするサブクラスでは false
に設定する必要があります。この変数が正しく設定されていない場合、commit メソッドはサブジェクトを正しく更新しません。
例18.24 AbstractServerLoginModule クラスの一部
package org.jboss.security.auth.spi; /** * This class implements the common functionality required for a JAAS * server-side LoginModule and implements the PicketBox standard * Subject usage pattern of storing identities and roles. Subclass * this module to create your own custom LoginModule and override the * login(), getRoleSets(), and getIdentity() methods. */ public abstract class AbstractServerLoginModule implements javax.security.auth.spi.LoginModule { protected Subject subject; protected CallbackHandler callbackHandler; protected Map sharedState; protected Map options; protected Logger log; /** Flag indicating if the shared credential should be used */ protected boolean useFirstPass; /** * Flag indicating if the login phase succeeded. Subclasses that * override the login method must set this to true on successful * completion of login */ protected boolean loginOk; // ... /** * Initialize the login module. This stores the subject, * callbackHandler and sharedState and options for the login * session. Subclasses should override if they need to process * their own options. A call to super.initialize(...) must be * made in the case of an override. * * <p> * The options are checked for the <em>password-stacking</em> parameter. * If this is set to "useFirstPass", the login identity will be taken from the * <code>javax.security.auth.login.name</code> value of the sharedState map, * and the proof of identity from the * <code>javax.security.auth.login.password</code> value of the sharedState map. * * @param subject the Subject to update after a successful login. * @param callbackHandler the CallbackHandler that will be used to obtain the * the user identity and credentials. * @param sharedState a Map shared between all configured login module instances * @param options the parameters passed to the login module. */ public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { // ... } /** * Looks for javax.security.auth.login.name and * javax.security.auth.login.password values in the sharedState * map if the useFirstPass option was true and returns true if * they exist. If they do not or are null this method returns * false. * Note that subclasses that override the login method * must set the loginOk var to true if the login succeeds in * order for the commit phase to populate the Subject. This * implementation sets loginOk to true if the login() method * returns true, otherwise, it sets loginOk to false. */ public boolean login() throws LoginException { // ... } /** * Overridden by subclasses to return the Principal that * corresponds to the user primary identity. */ abstract protected Principal getIdentity(); /** * Overridden by subclasses to return the Groups that correspond * to the role sets assigned to the user. Subclasses should * create at least a Group named "Roles" that contains the roles * assigned to the user. A second common group is * "CallerPrincipal," which provides the application identity of * the user rather than the security domain identity. * * @return Group[] containing the sets of roles */ abstract protected Group[] getRoleSets() throws LoginException; }
UsernamePasswordLoginModule
カスタムログインモジュールに適した 2 番目の抽象ベースログインモジュールは、org.jboss.security.auth.spi.UsernamePasswordLoginModule
です。
char
パスワードを認証資格情報として適用することにより、カスタムログインモジュールの実装をさらに簡素化します。また、匿名ユーザー (null のユーザー名とパスワードで示される) のロールのないプリンシパルへのマッピングもサポートします。クラスの重要な詳細は、次のクラスフラグメントで強調表示されています。JavaDoc コメントは、サブクラスの責任について詳しく説明しています。
例18.25 UsernamePasswordLoginModule クラスの一部
package org.jboss.security.auth.spi; /** * An abstract subclass of AbstractServerLoginModule that imposes a * an identity == String username, credentials == String password * view on the login process. Subclasses override the * getUsersPassword() and getUsersRoles() methods to return the * expected password and roles for the user. */ public abstract class UsernamePasswordLoginModule extends AbstractServerLoginModule { /** The login identity */ private Principal identity; /** The proof of login identity */ private char[] credential; /** The principal to use when a null username and password are seen */ private Principal unauthenticatedIdentity; /** * The message digest algorithm used to hash passwords. If null then * plain passwords will be used. */ private String hashAlgorithm = null; /** * The name of the charset/encoding to use when converting the * password String to a byte array. Default is the platform's * default encoding. */ private String hashCharset = null; /** The string encoding format to use. Defaults to base64. */ private String hashEncoding = null; // ... /** * Override the superclass method to look for an * unauthenticatedIdentity property. This method first invokes * the super version. * * @param options, * @option unauthenticatedIdentity: the name of the principal to * assign and authenticate when a null username and password are * seen. */ public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { super.initialize(subject, callbackHandler, sharedState, options); // Check for unauthenticatedIdentity option. Object option = options.get("unauthenticatedIdentity"); String name = (String) option; if (name != null) { unauthenticatedIdentity = new SimplePrincipal(name); } } // ... /** * A hook that allows subclasses to change the validation of the * input password against the expected password. This version * checks that neither inputPassword or expectedPassword are null * and that inputPassword.equals(expectedPassword) is true; * * @return true if the inputPassword is valid, false otherwise. */ protected boolean validatePassword(String inputPassword, String expectedPassword) { if (inputPassword == null || expectedPassword == null) { return false; } return inputPassword.equals(expectedPassword); } /** * Get the expected password for the current username available * via the getUsername() method. This is called from within the * login() method after the CallbackHandler has returned the * username and candidate password. * * @return the valid password String */ abstract protected String getUsersPassword() throws LoginException; }
ログインモジュールのサブクラス化
AbstractServerLoginModule
と UsernamePasswordLoginModule
のサブクラスの選択は、ログインモジュールを作成する認証テクノロジーで文字列ベースのユーザー名と資格情報を使用できるかどうかに基づいています。文字列ベースのセマンティクスが有効な場合は、UsernamePasswordLoginModule
をサブクラス化し、そうでない場合は、AbstractServerLoginModule
をサブクラス化します。
サブクラス化の手順
カスタムログインモジュールが実行する必要のある手順は、選択した基本ログインモジュールクラスによって異なります。セキュリティーインフラストラクチャーと統合するカスタムログインモジュールを作成するときは、AbstractServerLoginModule
または UsernamePasswordLoginModule
をサブクラス化して、ログインモジュールが EAP セキュリティーマネージャーが期待する形式で認証された プリンシパル
情報を提供するようにする必要があります。
AbstractServerLoginModule
をサブクラス化するときは、以下をオーバーライドする必要があります。
void initialize (Subject、CallbackHandler、Map、Map)
: 解析するカスタムオプションがある場合。boolean login ()
: 認証アクティビティーを実行します。ログインが成功した場合はloginOk
インスタンス変数を true に設定し、失敗した場合は false に設定してください。Principal getIdentity ()
:log ()
ステップによって認証されたユーザーのPrincipal
オブジェクトを返します。Group getRoleSets ()
:login ()
中に認証されたプリンシパル
に割り当てられたロールを含むRoles
という名前のグループ
を少なくとも 1 つ返します。2 番目の共通グループ
はCallerPrincipal
という名前で、セキュリティードメイン ID ではなくユーザーのアプリケーション ID を提供します。
UsernamePasswordLoginModule
をサブクラス化するときは、以下をオーバーライドする必要があります。
void initialize (Subject、CallbackHandler、Map、Map)
: 解析するカスタムオプションがある場合。Group getRoleSets ()
:login ()
中に認証されたプリンシパル
に割り当てられたロールを含むRoles
という名前のグループ
を少なくとも 1 つ返します。2 番目の共通グループ
はCallerPrincipal
という名前で、セキュリティードメイン ID ではなくユーザーのアプリケーション ID を提供します。String getUsersPassword ()
:getUsername ()
メソッドを介して使用可能な現在のユーザー名の予想されるパスワードを返します。getUsersPassword ()
メソッドは、callbackhandler
がユーザー名と候補パスワードを返した後、login ()
内から呼び出されます。