14.2. カスタムモジュール
AuthenticationManager では、Subject プリンシパルの特定の使用パターンが必要です。AuthenticationManager で動作するログインモジュールを作成するには、JAAS Subject クラスの情報ストレージ機能と、これらの機能の予想される使用方法を理解している。
LoginModule 実装を紹介します。
Subject に関連するセキュリティー情報を取得できます。
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)
Subject identity および roles の場合、EAP は最も論理的に選択されています。これは、getPrincipals()および getPrincipals (java.lang.Class) で取得したプリンシパルセットです。使用パターンは以下のとおりです。
- ユーザー ID(ユーザー名、ソーシャルセキュリティー番号、従業員 ID など)は、
サブジェクトプリンシパルセットにjava.security.Principalオブジェクトとして保存されます。ユーザー ID を表すPrincipal実装は、プリンシパルの名前に対するベース比較と等価でなければなりません。org.jboss.security.SimplePrincipalクラスとして適切な実装を利用できます。他のプリンシパルインスタンスは、必要に応じて設定されたSubjectPrincipalsに追加できます。 - 割り当てられたユーザーロールは
Principalsセットに保存され、java.security.acl.Groupインスタンスを使用して名前付きのロールセットにグループ化されます。GroupインターフェースはPrincipals またはGroupのコレクションを定義し、java.security.Principalのサブインターフェースです。 サブジェクトには任意の数のロールセットを割り当てることができます。
- EAP セキュリティーフレームワークは、
RolesとCallerPrincipalという名前の 2 つのよく知られたロールセットを使用します。Rolesグループは、Subjectが認証されたアプリケーションドメインで既知の名前付きロールのPrincipalのコレクションです。このロールセットは、ejb.isCallerInRole(String)などのメソッドによって使用されます。EJB は、現在の呼び出し元が名前付きのアプリケーションドメインロールに属するかどうかを確認するために使用できます。メソッドパーミッションチェックを実行するセキュリティーインターセプターロジックは、このロールセットも使用します。CallerPrincipalグループは、アプリケーションドメインのユーザーに割り当てられる単一のPrincipalアイデンティティーで構成されます。gitops.getCallerPrincipal()メソッドはCallerPrincipalを使用して、アプリケーションドメインのオペレーション環境アイデンティティーからアプリケーションに適したユーザー ID へのマッピングを許可します。SubjectにCallerPrincipalGroupがない場合、アプリケーションのアイデンティティーは動作する環境アイデンティティーと同じです。
14.2.1. Subject Usage パターンのサポート リンクのコピーリンクがクリップボードにコピーされました!
Subject Usage パターンの正しい実装を簡素化するために、EAP には、認証された Subject に正しいサブジェクトの使用を強制するテンプレートパターンを設定するログインモジュールが含まれます。
AbstractServerLoginModule
この 2 つの最も一般的なものは org.jboss.security.auth.spi.AbstractServerLoginModule クラスです。
javax.security.auth.spi.LoginModule インターフェースの実装を提供し、オペレーション環境セキュリティーインフラストラクチャーに固有のキータスクに抽象メソッドを提供します。クラスの主要な詳細は、例14.20「AbstractServerLoginModule Class Fragment」 で強調表示されています。JavaDoc コメントでは、サブクラスの責任が詳細に説明されています。
loginOk インスタンス変数はピボットです。これは、ログインに成功する場合は true に設定する必要があります。または、ログインメソッドを上書きするすべてのサブクラスで false に設定する必要があります。この変数が正しく設定されている場合、コミットメソッドはサブジェクトを正しく更新しません。
例14.20 AbstractServerLoginModule Class Fragment
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 コメントでは、サブクラスの責任が詳細に説明されています。
例14.21 UsernamePasswordLoginModule Class Fragment
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。
サブクラスの手順
カスタムログインモジュールを実行する必要がある手順は、選択したベースログインモジュールクラスによって異なります。セキュリティーインフラストラクチャーと統合するカスタムログインモジュールを作成する場合は、EAP セキュリティーマネージャーが想定される形式でログインモジュールが認証された Principal 情報を提供できるように、AbstractServerLoginModule または UsernamePasswordLoginModule をサブクラス化して開始する必要があります。
AbstractServerLoginModule をサブクラス化する場合は、以下を上書きする必要があります。
void initialize(Subject, CallbackHandler, Map, Map): 解析するカスタムオプションがある場合は。boolean login(): 認証アクティビティーを実行する。ログインに成功したら、loginOkインスタンス変数を true に設定してください。失敗した場合は false に設定します。プリンシパル getIdentity():log()ステップで認証されたユーザーのPrincipalオブジェクトを返します。group[] getRoleSets():login()時に認証された。2 つ目のPrincipalに割り当てられたロールが含まれるRolesという名前のグループを 1 つ以上返します共通グループはCallerPrincipalという名前で、セキュリティードメインアイデンティティーではなくユーザーのアプリケーションアイデンティティーを提供します。
UsernamePasswordLoginModule をサブクラス化する場合、以下を上書きする必要があります。
void initialize(Subject, CallbackHandler, Map, Map): 解析するカスタムオプションがある場合は。group[] getRoleSets():login()時に認証された。2 つ目のPrincipalに割り当てられたロールが含まれるRolesという名前のグループを 1 つ以上返します共通グループはCallerPrincipalという名前で、セキュリティードメインアイデンティティーではなくユーザーのアプリケーションアイデンティティーを提供します。string getUsersPassword():getUsername()メソッドで利用可能な現在のユーザー名の想定されるパスワードを返します。getUsersPassword()メソッドは、callbackhandlerがユーザー名およびパスワードを返した後にlogin()内で呼び出されます。