Red Hat Training

A Red Hat training course is available for Red Hat JBoss Enterprise Application Platform

18.3.2. カスタムモジュール

EAP セキュリティーフレームワークにバンドルされているログインモジュールがセキュリティー環境で機能しない場合は、独自のカスタムログインモジュール実装を作成できます。AuthenticationManager は、Subject プリンシパルの特定の使用パターンを必要とします。AuthenticationManager と動作するログインモジュールを作成するには、JAAS Subject クラスの情報ストレージ機能と、これらの機能の想定される使用方法を完全に理解する必要があります。
このセクションでは、この要件を検証し、カスタムログインモジュールの実装に役立つ 2 つの抽象ベース 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 セキュリティーフレームワークは、RolesCallerPrincipal という名前の 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 です。

このログインモジュールは、文字列ベースのユーザー名をユーザー ID として、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;
}

ログインモジュールのサブクラス化

AbstractServerLoginModuleUsernamePasswordLoginModule のサブクラスの選択は、ログインモジュールを作成する認証テクノロジーで文字列ベースのユーザー名と資格情報を使用できるかどうかに基づいています。文字列ベースのセマンティクスが有効な場合は、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 () 内から呼び出されます。