プライマリ・コンテンツに移動
Oracle® Fusion Middleware Oracle WebLogic Serverセキュリティ・プロバイダの開発 12c
12c (12.2.1.3.0)
E90323-01
目次へ移動
目次

前
次

4 認証プロバイダ

この章では、認証プロバイダの概念と機能、およびカスタム認証プロバイダの開発手順について説明します。

認証は、呼出し側が、特定のユーザーまたはシステムのかわりに動作していることを証明する際に使用するメカニズムです。認証は、ユーザー名とパスワードの組合せなどの資格証明を使用して「あなたは誰」という問いに答えます。

WebLogic Serverでは、ユーザーまたはシステム・プロセスのIDを証明するために認証プロバイダを使用します。認証プロバイダでは、ID情報を記憶したり、トランスポートしたり、その情報が必要な場合にサブジェクトを通じてシステムの様々なコンポーネントで利用できるようにしたりします。認証プロセスでは、プリンシパル検証プロバイダが、サブジェクト内に格納されるプリンシパル(ユーザーおよびグループ)のセキュリティを強化するため、それらのプリンシパルに署名して信頼性を検証します。(「プリンシパル検証プロバイダ」を参照してください。)

この章の内容は次のとおりです。

認証の概念

カスタム認証プロバイダの開発の詳細に立ち入る前に、次の概念を理解しておくことが大切です。

ユーザー/グループ、プリンシパル、サブジェクト

ユーザーは、人を表すという点でオペレーティング・システムのユーザーに似ています。一方、グループはユーザーのカテゴリで、肩書きなどの共通の特徴で分類されたものです。ユーザーをグループに分類すると、多数のユーザーに対するアクセス許可を管理しやすくなります。『Oracle WebLogic Serverロールおよびポリシーによるリソースの保護』のユーザー、グループおよびセキュリティ・ロールに関する項を参照してください。

WebLogic Serverのようなアプリケーション・サーバーでは、ユーザーもグループもプリンシパルとして使用することができます。プリンシパルは、認証の結果としてユーザーまたはグループに割り当てられるIDです。JAAS (Java Authentication and Authorization Service)では、プリンシパルなどの認証情報のコンテナとしてサブジェクトを使用することになっています。同じサブジェクト内に格納されている各プリンシパルは、ある人の財布に入っている複数のカードのように、同じユーザーのIDを異なる観点で表しています。たとえば、持ち主の身元を銀行に示すためにATMカードがあり、所属する組織に示すためにメンバーシップ・カードがある、という具合です。「Java Authentication and Authorization Service (JAAS)」を参照してください。

注意:

サブジェクトは、WebLogic Server 6.xのユーザーに取ってかわるものです。

図4-1に、ユーザー、グループ、プリンシパル、およびサブジェクト間の関係を示します。

図4-1 ユーザー、グループ、プリンシパル、およびサブジェクト間の関係

図4-1の説明が続きます
「図4-1 ユーザー、グループ、プリンシパル、およびサブジェクト間の関係」の説明

認証に成功すると、その一環として、プリンシパルは署名され、その後の使用に備えてサブジェクトに格納されます。プリンシパルに署名するのはプリンシパル検証プロバイダであり、実際にプリンシパルをサブジェクトに格納するのは認証プロバイダのLoginModuleです。後で、サブジェクト内に格納されたプリンシパルに呼出し側がアクセスしようとすると、そのプリンシパルが署名されてから変更されていないことをプリンシパル検証プロバイダが確認したうえで、そのプリンシパルが呼出し側に返されます(それ以外のセキュリティ条件がすべて満たされている場合)。

注意:

「プリンシパル検証プロバイダ」および「LoginModules」をそれぞれ参照してください。

WebLogic Serverユーザーまたはグループを表すプリンシパルは、weblogic.security.spiパッケージのWLSUserインタフェースとWLSGroupインタフェースを実装する必要があります。

初期ユーザーおよびグループの指定

認証プロバイダでは、実行中のWebLogic Serverで認証を実行する前にユーザーとグループのリストが必要です。一部の認証プロバイダを使用すると、管理者は外部データベースを構成し(LDAPサーバーまたはDBMSにユーザーおよびグループを追加するなど)、そのデータベースを使用するようにプロバイダを構成できます。管理者が外部データベースのツールを使用してユーザーとグループをあらかじめ指定するので、これらのプロバイダはどのようにユーザーとグループが指定されたかを認識する必要はありません。

ただし、一部の認証プロバイダは、独自のユーザーとグループのリストを作成および管理します。ManageableSampleAuthenticatorプロバイダがそれに当てはまります。この場合、認証プロバイダは、ユーザーとグループの初期セットがどのように指定されたかを認識する必要があります。これを行う方法としては、プロバイダの初期化メソッドで、ユーザーとグループがまだないことを通知し、ユーザーとグループの初期セットを指定してリストを作成するというものがあります。

一部のプロバイダは、セキュリティ・レルムごとにユーザーとグループの個別のリストを持っているので、新しいレルムで最初にリストを使用する場合に、ユーザーとグループの初期セットを作成する必要があります。たとえば、ManageableSampleAuthenticatorプロバイダは、ユーザーとグループの個別のプロパティ・ファイルをレルムごとに作成します。この認証プロバイダのinitializeメソッドは、レルム名を取得して、そのレルムのプロパティ・ファイルが存在するかどうかを判別し、存在しない場合は、ユーザーとグループの初期セットでプロパティ・ファイルを作成します。

LoginModule

LoginModuleは、認証プロバイダの必須コンポーネントであり、境界認証用に別個のLoginModuleを開発する必要がある場合はIDアサーション・プロバイダのコンポーネントにもなります。

LoginModuleは、認証処理における「馬車馬」のような存在です。すべてのLoginModuleは、セキュリティ・レルム内のユーザーの認証と、サブジェクト内への必要なプリンシパル(ユーザー/グループ)の格納を担当します。境界認証に使用されないLoginModuleも、提示された証明情報(たとえば、ユーザーのパスワード)が正しいかどうかを確認します。

注意:

「IDアサーション・プロバイダ」を参照してください。

セキュリティ・レルムに複数の認証プロバイダが構成されている場合、各認証プロバイダのLoginModuleは同じサブジェクトにプリンシパルを格納します。したがって、ある認証プロバイダのLoginModuleによって、WebLogic Serverユーザー(WLSUserインタフェースの実装)を表すプリンシパル「Joe」がサブジェクトに追加された場合、セキュリティ・レルム内の他のすべての認証プロバイダは、「Joe」に出会ったときに同じ人物を参照する必要があります。つまり、他の認証プロバイダのLoginModuleは、同じ人物を参照するために、WebLogic Serverユーザーを表す別のプリンシパル(「Joseph」など)をサブジェクトに追加しようとしてはなりません。ただし、別の認証プロバイダのLoginModuleは、WLSUser以外のタイプのプリンシパルを「Joseph」という名前で追加することができます。

LoginModuleインタフェース

LoginModuleは、ユーザー名とパスワードの組合せ、スマート・カード、バイオメトリック装置などの様々な認証メカニズムを扱うように作成することができます。LoginModuleを開発するには、JAAS (Java Authentication and Authorization Service)に基づき、認証情報のコンテナとしてサブジェクトを使用するjavax.security.auth.spi.LoginModuleインタフェースを実装します。LoginModuleインタフェースを使用すると、単一アプリケーション用に様々な種類の認証技術をプラグインすることができ、WebLogicセキュリティ・フレームワークはマルチパート認証用に複数のLoginModule実装をサポートするように設計されています。さらに、LoginModuleインスタンス間に依存関係を設けたり、それらのインスタンス間で資格証明を共有することもできます。ただし、LoginModuleと認証プロバイダの関係は1対1です。つまり、網膜スキャン認証を扱うLoginModuleと、スマート・カードのようなハードウェア・デバイスとのインタフェースを取るLoginModuleを用意するには、それぞれにLoginModuleインタフェースの実装が含まれる2つの認証プロバイダを開発して構成する必要があります。「JAAS LoginModuleインタフェースの実装」を参照してください。

注意:

LoginModuleは、独自に開発するのではなくサード・パーティのセキュリティ・ベンダーから入手することもできます。

LoginModuleとマルチパート認証

複数の認証プロバイダ(その結果として複数のLoginModule)を構成する方法は、認証プロセスの全体的な結果に影響します。これは、様々な要素からなる認証で特に重要です。まず、LoginModuleは認証プロバイダのコンポーネントであるため、認証プロバイダが構成された順序で呼び出されます。通常、認証プロバイダの構成には、WebLogic Server管理コンソールを使用します。(「認証プロバイダの順序の指定」を参照してください。)次に、各LoginModuleの制御フラグがどのように設定されるかによって、認証プロセスでのエラーの処理方法が決まります。図4-2は、それぞれ別の認証プロバイダに属する3つのLoginModuleが関わるサンプル・フローを示すとともに、様々な認証結果でサブジェクトに何が起こるのかを示しています。

図4-2 LoginModuleのサンプル・フロー

図4-2の説明が続きます
「図4-2 LoginModuleのサンプル・フロー」の説明

カスタム認証プロバイダ#1の制御フラグがREQUIREDに設定されていた場合、ユーザー認証ステップで認証が失敗すると、認証プロセス全体が失敗します。また、ユーザーがWebLogic認証プロバイダ(またはカスタム認証プロバイダ#2)によって認証されなかった場合、認証プロセス全体が失敗します。認証プロセスがこのように失敗した場合、3つのLoginModuleすべてがロールバックされ、サブジェクトにプリンシパルが格納されません。

注意:

Java Authentication and Authorization Service (JAAS) LoginModule開発者ガイド(http://docs.oracle.com/javase/8/docs/technotes/guides/security/jaas/JAASLMDevGuide.html)およびLoginModuleインタフェースに関する項(http://docs.oracle.com/javase/8/docs/api/javax/security/auth/spi/LoginModule.html)をそれぞれ参照してください。

JAAS (Java Authentication and Authorization Service)

クライアントが認証の必要なアプリケーション、アプレット、Enterprise JavaBean (EJB)、あるいはサーブレットのいずれであろうと、WebLogic Serverでは、JAAS (Java Authentication and Authorization Service)クラスを用いて、信頼性とセキュリティを確保しつつクライアントに対する認証を行います。JAASは、プラガブルな認証モジュール(PAM)フレームワークのJavaバージョンを実装します。このフレームワークにより、アプリケーションは基底の認証技術から独立することができます。このため、PAMフレームワークを利用することで、アプリケーションに修正を加えることなく新しいまたは更新された認証技術を使用することができます。

WebLogic Serverは、リモートのファット・クライアントの認証および内部の認証でJAASを使用します。したがって、JAASに直に関与する必要があるのは、カスタム認証プロバイダの開発者とリモート・ファット・クライアント・アプリケーションの開発者だけです。シン・クライアントのユーザーまたはコンテナ内のファット・クライアント・アプリケーション(サーブレットからEnterprise JavaBeanを呼び出すものなど)の開発者は、JAASを直接使用したり、その知識を身につけたりする必要はありません。

JAASがWebLogicセキュリティ・フレームワークとどう連携するか

通常、JAASクラスとWebLogicセキュリティ・フレームワークを用いた認証は、以下のように実行されます:

  1. クライアント側アプリケーションがユーザーまたはシステム・プロセスから認証情報を取得します。このときのメカニズムは、クライアントのタイプごとに異なります。

  2. クライアント側アプリケーションでは、認証情報が格納されたCallbackHandlerを任意に作成できます。

    1. クライアント側アプリケーションは、LoginContextクラスを使用してCallbackHandlerをローカル(クライアント側) LoginModuleに渡します。ローカルLoginModuleは、WebLogic Serverの一部として提供されているUsernamePasswordLoginModuleの場合があります。

    2. ローカルLoginModuleは、認証情報が格納されたCallbackHandlerを適切なWebLogic Serverコンテナ(RMI、EJB、サーブレット、IIOPなど)に渡します。

      注意:

      CallbackHandlerは、可変個の引数を複合オブジェクトとしてメソッドに渡すことができるようにする高度に柔軟なJAAS規格です。CallbackHandlerのタイプは、NameCallback、PasswordCallback、およびTextInputCallbackの3つで、いずれもjavax.security.auth.callbackパッケージに収められています。NameCallbackとPasswordCallbackは、それぞれユーザー名とパスワードを返します。TextInputCallbackは、ユーザーがログイン・フォームの追加フィールド(ユーザー名とパスワードを取得するフィールド以外のフィールド)に入力したデータにアクセスするために使用します。TextInputCallbackはフォームの追加フィールドにつき1つ必要で、各TextInputCallbackのプロンプト文字列はフォームのフィールド名と一致する必要があります。WebLogic Serverは、フォームベースのWebアプリケーション・ログインに対してのみTextInputCallbackを使用します。CallbackHandlerインタフェースに関する項(http://docs.oracle.com/javase/8/docs/api/javax/security/auth/callback/CallbackHandler.html)を参照してください。

      LoginContextクラスに関する項(http://docs.oracle.com/javase/8/docs/api/javax/security/auth/login/LoginContext.html)を参照してください。

      WebLogic Server APIリファレンス(Javadoc)UsernamePasswordLoginModuleクラスに関する項を参照してください。

      クライアント側LoginModuleを使用しない場合、ユーザー名とパスワードを他の方法で(たとえば初期JNDIルックアップの一部として)指定できます。

  3. WebLogic Serverコンテナは、WebLogicセキュリティ・フレームワークに働きかけを行います。認証情報が格納されたクライアント側CallbackHandlerが存在する場合、それがWebLogicセキュリティ・フレームワークに渡されます。

  4. WebLogicセキュリティ・フレームワークにより、渡された認証情報を使用して、構成されている認証プロバイダごとにCallbackHandlerが作成されます。これらはWebLogicセキュリティ・フレームワークによってサーバー側に作成された内部的なCallbackHandlerであり、クライアントのCallbackHandlerとは関係ありません。

  5. WebLogicセキュリティ・フレームワークは、認証プロバイダに関連付けられたLoginModule (認証情報を処理するために指定された特定のLoginModule)を呼び出します。

    注意:

    「LoginModules」を参照してください。

    LoginModuleが認証情報を利用してクライアントを認証しようとします。

  6. 認証に成功すると、以下の処理が行われます。

    1. プリンシパル検証プロバイダによってプリンシパル(ユーザーおよびグループ)が署名され、プログラムによるサーバー呼出し間での信頼性が確保されます。「プリンシパル検証プロバイダ」を参照してください。

    2. LoginModuleは署名済みのプリンシパルをサブジェクトに関連付けます。そのオブジェクトが認証対象のユーザーまたはシステム・プロセスを表します。「ユーザー/グループ、プリンシパル、サブジェクト」を参照してください。

      注意:

      サーバー側ですべてが行われる認証の場合、プロセスはステップ3から始まり、WebLogic Serverコンテナはステップ4の前にweblogic.security.services.authentication.loginメソッドを呼び出します。

例:スタンドアロンのT3アプリケーション

スタンドアロンのT3アプリケーションの場合にJAASクラスがWebLogicセキュリティ・フレームワークとどう連携するかを図4-3に示し、続いてそれについて説明します。

図4-3 JAASクラスとWebLogic Serverを用いた認証

図4-3の説明が続きます
「図4-3 JAASクラスとWebLogic Serverを用いた認証」の説明

この例で、JAASクラスとWebLogicセキュリティ・フレームワークを用いた認証は以下のように実行されます。

  1. T3アプリケーションがユーザーまたはシステム・プロセスから認証情報(ユーザー名、パスワード、およびURL)を取得します。

  2. T3アプリケーションは、認証情報が格納されたCallbackHandlerを作成します。

    1. T3アプリケーションは、LoginContextクラスを使用してCallbackHandlerUsernamePasswordLoginModuleに渡します。

      注意:

      weblogic.security.auth.login.UsernamePasswordLoginModuleは標準のJAAS javax.security.auth.spi.LoginModuleインタフェースを実装し、クライアント側のAPIを使用してWebLogic Serverインスタンスに対するWebLogicクライアントの認証を行います。これは、T3クライアントとIIOPクライアントの両方で使用できます。このLoginModuleの呼出し側では、CallbackHandlerを実装してユーザー名(NameCallback)、パスワード(PasswordCallback)、およびURL (URLCallback)を渡す必要があります。

    2. UsernamePasswordLoginModuleは、認証情報(ユーザー名、パスワード、およびURL)が格納されたCallbackHandlerをWebLogic Server RMIコンテナに渡します。

  3. WebLogic Server RMIコンテナは、WebLogicセキュリティ・フレームワークに働きかけを行います。認証情報が格納されたクライアント側CallbackHandlerがWebLogicセキュリティ・フレームワークに渡されます。

  4. WebLogicセキュリティ・フレームワークにより、渡されたユーザー名、パスワード、およびURLの格納されたCallbackHandlerが、構成されている認証プロバイダごとに作成されます。これらはWebLogicセキュリティ・フレームワークによってサーバー側に作成された内部的なCallbackHandlerであり、クライアントのCallbackHandlerとは関係ありません。

  5. WebLogicセキュリティ・フレームワークは、認証プロバイダに関連付けられたLoginModule (認証情報を処理するために指定された特定のLoginModule)を呼び出します。

    LoginModuleが認証情報を利用してクライアントを認証しようとします。

  6. 認証に成功すると、以下の処理が行われます。

    1. プリンシパル検証プロバイダによってプリンシパル(ユーザーおよびグループ)が署名され、プログラムによるサーバー呼出し間での信頼性が確保されます。

    2. LoginModuleは署名済みのプリンシパルをサブジェクトに関連付けます。そのオブジェクトが認証対象のユーザーまたはシステムを表します。

    3. WebLogicセキュリティ・フレームワークは認証ステータスをT3クライアント・アプリケーションに返し、T3クライアント・アプリケーションは認証済みのサブジェクトをWebLogicセキュリティ・フレームワークから受け取ります。

認証プロセス

図4-4に、ファット・クライアント・ログインの認証プロセスの仕組みを示します。JAASはサーバー上で動作してログインを実行します。シン・クライアント・ログイン(ブラウザ・クライアント)の場合でも、JAASはサーバー上で動作します。

注意:

JAASプロセスを直接扱うのは、カスタム認証プロバイダの開発者だけです。クライアント・アプリケーションは、JNDI初期コンテキスト作成またはJAASのいずれかを使用してユーザー名とパスワードを受け渡します。

ユーザーがユーザー名とパスワードの組合せを使用してシステムにログインしようとすると、WebLogic Serverはそのユーザーのユーザー名とパスワードを検証することによって信頼を確立し、JAASの要件に従って、プリンシパルが格納されたサブジェクトを返します。図4-4にも表示されているように、このプロセスでは、LoginModuleとプリンシパル検証プロバイダを使用する必要があります。詳細は、「LoginModule」および「プリンシパル検証プロバイダ」をそれぞれ参照してください。

呼出し側のIDの確認に成功すると、認証コンテキストが確立され、IDが確認されたユーザーまたはシステムに関しては、そのコンテキストを通じて他のエンティティに対する認証を行うことができます。認証コンテキストはまた、アプリケーション・コンポーネントに委託することもでき、それによって、そのコンポーネントは別のアプリケーション・コンポーネントを呼び出しつつ、元の呼出し側として動作できるようになります。

カスタム認証プロバイダを開発する必要があるか

WebLogic Serverのデフォルト(アクティブ)セキュリティ・レルムには、WebLogic認証プロバイダが含まれます。

注意:

WebLogic認証プロバイダをWebLogic認可プロバイダと組み合せれば、WebLogic Serverリリース6.xで利用できたファイル・レルムの機能のかわりになります。

WebLogic認証プロバイダは、ユーザー名とパスワードの委託認証をサポートし、組込みLDAPサーバーを利用してユーザーとグループの情報を格納します。WebLogic認証プロバイダを使用すると、ユーザーとグループ・メンバーシップを編集、表示、および管理できます。

WebLogic Serverでは、デフォルトのセキュリティ・レルムにおいて、次の認証プロバイダをWebLogic認証プロバイダのかわりとして使用したり、WebLogic認証プロバイダと併用したりすることもできます。

  • Open LDAP、iPlanet、Microsoft Active Directory、およびNovell NDSといった外部LDAPストアにアクセスする一連のLDAP認証プロバイダ

  • 認証を行うために、データベースに格納されているユーザー、パスワード、グループ、およびグループ・メンバーシップ情報にアクセスする一連のデータベース管理システム(DBMS)プロバイダ

  • 認証を行うためにWindows NTユーザーおよびグループを使用するWindows NT認証プロバイダ

  • LDAP X509 IDアサーション・プロバイダ

デフォルトでは、これらの認証プロバイダは使用可能ですが、WebLogicデフォルト・セキュリティ・レルムには構成されていません。

追加の認証タスクを実行する場合は、カスタム認証プロバイダを開発する必要があります。

注意:

初期状態ではサポートされていない種類のトークン(新規、カスタム、サード・パーティのトークンなど)を使用して境界認証を行うには、カスタムIDアサーション・プロバイダを開発する必要があります。「IDアサーション・プロバイダ」を参照してください。

カスタム認証プロバイダの開発方法

WebLogic認証プロバイダが開発者のニーズを満たさない場合、次の手順でカスタム認証プロバイダを開発することができます。

  1. 適切なSSPIによるランタイム・クラスの作成

  2. 「WebLogic MBeanMakerを使用してMBeanタイプを生成する」で説明されている手順を実行してカスタム認証プロバイダのMBeanタイプを生成

  3. 管理コンソールによるカスタム認証プロバイダの構成

適切なSSPIによるランタイム・クラスの作成

ランタイム・クラスを作成する前に、以下の作業が必要です。

この情報を理解し、設計に関する判断を下したら、次の手順でカスタム認証プロバイダのランタイム・クラスを作成します。

カスタム認証プロバイダのランタイム・クラスの作成例については、「例:サンプル認証プロバイダのランタイム・クラスの作成」を参照してください。

AuthenticationProviderV2 SSPIの実装

注意:

AuthenticationProvider SSPIは、このリリースのWebLogic Serverでは非推奨になっています。AuthenticationProviderV2 SSPIをかわりに使用してください。

AuthenticationProviderV2 SSPIを実装するには、Provider SSPIの目的についてで説明されているメソッドおよび次のメソッドの実装を提供する必要があります。

  • getLoginModuleConfiguration

    public AppConfigurationEntry getLoginModuleConfiguration()
    

    getLoginModuleConfigurationメソッドは、認証プロバイダの関連付けられたLoginModuleに関する情報を取得します。その情報は、AppConfigurationEntryとして返されます。AppConfigurationEntryは、LoginModuleのクラス名、認証プロバイダの関連するMBeanを通じて渡されたLoginModuleの制御フラグ、および他の構成情報をLoginModuleに渡すことを可能にするLoginModuleの構成オプション・マップの格納されたJAAS (Java Authentication and Authorization Service)クラスです。

    (javax.security.auth.loginパッケージ内にある)AppConfigurationEntryクラスとLoginModulesの制御フラグ・オプションの詳細は、AppConfigurationEntryクラスに関する項(http://docs.oracle.com/javase/8/docs/api/javax/security/auth/login/AppConfigurationEntry.html)およびConfigurationクラスに関する項(http://docs.oracle.com/javase/8/docs/api/javax/security/auth/login/Configuration.html)を参照してください。「LoginModules」および「MBeanタイプが必要な理由について」を参照してください。

  • getAssertionModuleConfiguration

    public AppConfigurationEntry
    getAssertionModuleConfiguration()
    

    getAssertionModuleConfigurationメソッドは、IDアサーション・プロバイダの関連付けられたLoginModuleに関する情報を取得します。その情報は、AppConfigurationEntryとして返されます。AppConfigurationEntryは、LoginModuleのクラス名、IDアサーション・プロバイダの関連するMBeanを通じて渡されたLoginModuleの制御フラグ、および他の構成情報をLoginModuleに渡すことを可能にするLoginModuleの構成オプション・マップの格納されたJAASクラスです。

    注意:

    getAssertionModuleConfigurationメソッドの実装はnullを返す場合があります(IDアサーション・プロバイダが認証プロバイダと同じLoginModuleを使用する場合)。

    IDアサーション・プロバイダのassertIdentity()メソッドは、IDアサーションが発生するたびに呼び出されますが、サブジェクトがキャッシュされている場合、LoginModuleは呼び出されないことがあります。-Dweblogic.security.identityAssertionTTLフラグを使うと、この動作を変更する(たとえば、5分というデフォルトTTLを変更する、またはフラグを -1に設定してキャッシュを無効にする)ことができます。

    トークンが有効なだけでなく、ユーザーも引続き有効であること(ユーザーが削除されていないことなど)を確認するのは、IDアサーション・プロバイダの役割です。

    EJBの<run-as-principal>要素とカスタム認証プロバイダを併用する場合には、getAssertionModuleConfiguration()メソッドを使用します。このメソッドが実行するIDアサーションによって、<run-as-principal>要素に指定されているプリンシパルが検証されます。

  • getPrincipalValidator

    public PrincipalValidator getPrincipalValidator()
    

    getPrincipalValidatorメソッドは、プリンシパル検証プロバイダのランタイム・クラス(PrincipalValidator SSPI実装)の参照を取得します。WebLogicプリンシパル検証プロバイダは、ほとんどの場合に使用できます。WebLogicプリンシパル検証プロバイダの返し方の例については、例4-1を参照してください。「プリンシパル検証プロバイダ」を参照してください。

  • getIdentityAsserter

    public IdentityAsserterV2 getIdentityAsserter()
    

    AuthenticationProviderV2のgetIdentityAsserterメソッドは、新しいIDアサーション・プロバイダのランタイム・クラス(IdentityAsserterV2 SSPI実装)の参照を取得します。

    ほとんどの場合、このメソッドの戻り値はnullになります(例については例4-1を参照)。「IDアサーション・プロバイダ」を参照してください。

前述のAuthenticationProviderV2 SSPIおよびメソッドの詳細は、Oracle WebLogic Server Java APIリファレンスを参照してください。

JAAS LoginModuleインタフェースの実装

JAAS javax.security.auth.spi.LoginModuleインタフェースを実装するには、以下のメソッドを実装する必要があります。

  • initialize

    public void initialize (Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options)
    

    initializeメソッドはLoginModuleを初期化します。引数として取るのは、結果として得られるプリンシパルを格納するサブジェクト、認証プロバイダが認証情報のコンテナにコールバックするのに使用するCallbackHandler、任意の共有状態情報のマップ、および構成オプション(すなわち、LoginModuleに渡す任意の付加的情報)のマップです。

    CallbackHandlerは、可変個の引数を複合オブジェクトとしてメソッドに渡すことができるようにする高度に柔軟なJAAS規格です。Java SE 8.0 API仕様のCallbackHandlerインタフェースに関する項(http://docs.oracle.com/javase/8/docs/api/javax/security/auth/callback/CallbackHandler.html)を参照してください。

  • login

    public boolean login() throws LoginException
    

    loginメソッドは、ユーザーを認証し、認証情報のコンテナにコールバックすることでそのユーザーのプリンシパルを作成しようと試みます。複数のLoginModuleが複数の認証プロバイダの一部として構成されている場合、このメソッドはLoginModuleごとにその構成の順序で呼び出されます。ログインが成功したかどうか(すなわち、プリンシパルが作成されたかどうか)についての情報は、LoginModuleごとに格納されます。

  • commit

    public boolean commit() throws LoginException
    

    commitメソッドは、loginメソッドで作成されたプリンシパルをサブジェクトに追加しようと試みます。このメソッドも、構成されている認証プロバイダの一部として構成されているLoginModuleごとに呼び出され、順番に実行されます。コミットが成功したかどうかの情報は、LoginModuleごとに格納されます。

  • abort

    public boolean abort() throws LoginException
    

    abortメソッドは、構成されている認証プロバイダの一部として構成されているLoginModuleのコミットが失敗した(つまり、関連するREQUIREDREQUISITESUFFICIENT、およびOPTIONAL LoginModuleが成功しなかった)場合にLoginModuleごとに呼び出されます。abortメソッドは、LoginModuleのプリンシパルをサブジェクトから削除し、実行されたアクションを効果的にロールバックします。LoginModuleインタフェースに関する項(http://docs.oracle.com/javase/8/docs/api/javax/security/auth/spi/LoginModule.html)を参照してください。

  • logout

    public boolean logout() throws LoginException
    

    logoutメソッドは、ユーザーをシステムからログアウトさせようとします。また、サブジェクトのリセットも行うので、関連付けられているプリンシパルは格納されなくなります。

    注意:

    LoginModule.logoutメソッドはWebLogic認証プロバイダまたはカスタム認証プロバイダに対して呼び出されることはありません。これは単に、いったんプリンシパルが作成されサブジェクト内に入れられると、WebLogicセキュリティ・フレームワークはこのサブジェクトのライフサイクルを制御しなくなるからです。したがって、JAAS LoginContext を作成してログインおよびサブジェクトの取得を行う、開発者によって記述されたユーザー・コードでも、 LoginContext.logout メソッドを呼び出す必要があります。ユーザー・コードが、JAASを直接使用するJavaクライアントで実行される場合、このコードには LoginContext.logout メソッドを呼び出すというオプションがあります。これにより、サブジェクトはクリアされます。ユーザー・コードがサーブレットで実行される場合、サーブレットはサーブレット・セッションからユーザーをログアウトすることができます。これにより、サブジェクトはクリアされます。

Java Authentication and Authorization Service (JAAS)開発者ガイド(http://docs.oracle.com/javase/8/docs/technotes/guides/security/jaas/JAASLMDevGuide.html)およびLoginModuleインタフェースに関する項(http://docs.oracle.com/javase/8/docs/api/javax/security/auth/spi/LoginModule.html)を参照してください。

LoginModuleからカスタム例外のスロー

記述したLoginModuleからカスタム例外をスローすることができます。そうすると、カスタム例外をアプリケーションおよび、実行された適切なアクションで捕捉できます。たとえば、LoginModuleからPasswordChangeRequiredExceptionがスローされると、その例外をアプリケーションで捕捉して、パスワードの変更が可能なページへユーザーを導くのに使用できます。

LoginModuleからカスタム例外をスローし、それをアプリケーション内で捕捉する場合には、以下のことを確認する必要があります。

  1. 例外を捕捉するアプリケーションがサーバー上で実行されています。(ファット・クライアントはカスタム例外を捕捉できません。)

  2. サーブレットが、コンパイル時でもデプロイメント時でもカスタム例外クラスにアクセスできます。これは、必要に応じて次の方法のいずれかで行えます。

方法1 :システム・クラスパスおよびコンパイラ・クラスパスを介してカスタム例外を使えるようにする
  1. LoginExceptionを拡張する例外クラスを記述します。

  2. LoginModuleインタフェースおよびAuthenticationProviderインタフェースを実装するクラスでカスタム例外クラスを使用します。

  3. セキュリティ・プロバイダの ランタイム・クラスをコンパイルする際に、カスタム例外クラスをシステム・クラスパスおよびコンパイラ・クラスパスの両方に入れます。

  4. 「WebLogic MBeanMakerを使用してMBeanタイプを生成する」で説明されているようにカスタム認証プロバイダのMBeanタイプを生成します。

方法2 :アプリケーション・クラスパスを介してカスタム例外を使えるようにする

  1. LoginExceptionを拡張する例外クラスを記述します。

  2. LoginModuleインタフェースおよびAuthenticationProviderインタフェースを実装するクラスでカスタム例外クラスを使用します。

  3. カスタム例外のソースをアプリケーションのビルドのクラスパスに入れ、それをアプリケーションのJAR/WARファイルのクラスパスに含めます。

  4. 「WebLogic MBeanMakerを使用してMBeanタイプを生成する」で説明されているようにカスタム認証プロバイダのMBeanタイプを生成します。

  5. WebLogic MBeanMakerで生成されたMJF (MBean JARファイル)にカスタム例外クラスを追加します。

  6. アプリケーションのコンパイル時にMJFを含めます。

例:サンプル認証プロバイダのランタイム・クラスの作成

例4-1は、サンプル認証プロバイダの2つのランタイム・クラスの1つであるSimpleSampleAuthenticationProviderImpl.javaクラスを示しています。このランタイム・クラスには次の実装が含まれています。

  • initializegetDescriptionおよびshutdownというSecurityProviderインタフェースから継承した3つのメソッド(Provider SSPIの目的についてを参照。)

  • getLoginModuleConfigurationgetAssertionModuleConfigurationgetPrincipalValidator、およびgetIdentityAsserterというAuthenticationProviderV2 SSPIの4つのメソッド(「AuthenticationProviderV2 SSPIの実装」を参照)。

    注意:

    例4-1の太字のコードは、クラス宣言とメソッド・シグネチャを示しています。

例4-1 SimpleSampleAuthenticationProviderImpl.java

package examples.security.providers.authentication.simple;
import java.util.HashMap;
import javax.security.auth.login.AppConfigurationEntry;
import javax.security.auth.login.AppConfigurationEntry.LoginModuleControlFlag;
import weblogic.management.security.ProviderMBean;
import weblogic.security.spi.AuthenticationProviderV2;
import weblogic.security.spi.IdentityAsserterV2;
import weblogic.security.spi.PrincipalValidator;
import weblogic.security.spi.SecurityServices;
import weblogic.security.principal.WLSGroupImpl;
import weblogic.security.principal.WLSUserImpl;
public final class SimpleSampleAuthenticationProviderImpl implements AuthenticationProviderV2
{
   private String description;
   private SimpleSampleAuthenticatorDatabase database;
   private LoginModuleControlFlag controlFlag;
   public void initialize(ProviderMBean mbean, SecurityServices services)
   {
      System.out.println("SimpleSampleAuthenticationProviderImpl.initialize");
      SimpleSampleAuthenticatorMBean myMBean = (SimpleSampleAuthenticatorMBean)mbean;
      description = myMBean.getDescription() + "\n" + myMBean.getVersion();
      database = new SimpleSampleAuthenticatorDatabase(myMBean);
      String flag = myMBean.getControlFlag();
      if (flag.equalsIgnoreCase("REQUIRED")) {
        controlFlag = LoginModuleControlFlag.REQUIRED;
      } else if (flag.equalsIgnoreCase("OPTIONAL")) {
        controlFlag = LoginModuleControlFlag.OPTIONAL;
      } else if (flag.equalsIgnoreCase("REQUISITE")) {
        controlFlag = LoginModuleControlFlag.REQUISITE;
      } else if (flag.equalsIgnoreCase("SUFFICIENT")) {
        controlFlag = LoginModuleControlFlag.SUFFICIENT;
      } else {
        throw new IllegalArgumentException("invalid flag value" + flag);
      }
   }
   public String getDescription()
   {
      return description;
   }
   public void shutdown()
   {
      System.out.println("SimpleSampleAuthenticationProviderImpl.shutdown");
   }
   private AppConfigurationEntry getConfiguration(HashMap options)
   {
      options.put("database", database);
      return new 
        AppConfigurationEntry(
          "examples.security.providers.authentication.Simple.Simple.SampleLoginModuleImpl",
          controlFlag,
          options
        );
   }
   public AppConfigurationEntry getLoginModuleConfiguration()
   {
      HashMap options = new HashMap();
      return getConfiguration(options);
   }
   public AppConfigurationEntry getAssertionModuleConfiguration()
   {
      HashMap options = new HashMap();
      options.put("IdentityAssertion","true");
      return getConfiguration(options);
   }
   public PrincipalValidator getPrincipalValidator() 
   {
      return new PrincipalValidatorImpl();
   }
   public IdentityAsserterV2 getIdentityAsserter()
   {
      return null;
   }
}

例4-2は、サンプル認証プロバイダの2つのランタイム・クラスの1つであるSampleLoginModuleImpl.javaクラスを示しています。このランタイム・クラスは、JAAS LoginModuleインタフェースを実装するため(「JAAS LoginModuleインタフェースの実装」を参照)、そのinitializelogincommitabortおよびlogoutメソッドの実装を含んでいます。

注意:

例4-2の太字のコードは、クラス宣言とメソッド・シグネチャを示しています。

例4-2 SimpleSampleLoginModuleImpl.java

package examples.security.providers.authentication.simple;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Map;
import java.util.Vector;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginException;
import javax.security.auth.login.FailedLoginException;
import javax.security.auth.spi.LoginModule;
import weblogic.management.utils.NotFoundException;
import weblogic.security.spi.WLSGroup;
import weblogic.security.spi.WLSUser;
import weblogic.security.principal.WLSGroupImpl;
import weblogic.security.principal.WLSUserImpl;
final public class SimpleSampleLoginModuleImpl implements LoginModule 
{
   private Subject subject;
   private CallbackHandler callbackHandler;
   private SimpleSampleAuthenticatorDatabase database;
   // Determine whether this is a login or assert identity 
   private boolean isIdentityAssertion;
   // Authentication status
   private boolean loginSucceeded;
   private boolean principalsInSubject;
   private Vector principalsForSubject = new Vector();
   public void initialize(Subject subject, CallbackHandler callbackHandler, Map  
   sharedState, Map options) 
   {
      // only called (once!) after the constructor and before login
      System.out.println("SimpleSampleLoginModuleImpl.initialize");
      this.subject = subject;
      this.callbackHandler = callbackHandler;
      // Check for Identity Assertion option
      isIdentityAssertion =
         "true".equalsIgnoreCase((String)options.get("IdentityAssertion"));
      database = (SimpleSampleAuthenticatorDatabase)options.get("database");
   }
   public boolean login() throws LoginException  
   {
      // only called (once!) after initialize
      System.out.println("SimpleSampleLoginModuleImpl.login");
      // loginSucceeded       should be false
      // principalsInSubject  should be false

      Callback[] callbacks = getCallbacks();
      String userName = getUserName(callbacks);
      if (userName.length() > 0) {
         if (!database.userExists(userName)) {
            throwFailedLoginException("Authentication Failed: User " + userName 
            + " doesn't exist.");
         }
        if (!isIdentityAssertion) {
         String passwordWant = null;
         try {
            passwordWant = database.getUserPassword(userName);
         } catch (NotFoundException shouldNotHappen) {}
            String passwordHave = getPasswordHave(userName, callbacks);
            if (passwordWant == null || !passwordWant.equals(passwordHave)) {
               throwFailedLoginException(
                 "Authentication Failed: User " + userName + " bad password." 
               );
            }
         }
         } else { 
          // anonymous login - let it through?
         System.out.println("\tempty userName");
         }
         loginSucceeded = true;
         principalsForSubject.add(new WLSUserImpl(userName));
         addGroupsForSubject(userName);
         return loginSucceeded;
   }
   public boolean commit() throws LoginException 
   {
      // only called (once!) after login
      // loginSucceeded      should be true or false
      // principalsInSubject should be false
      // user      should be null if !loginSucceeded, null or not-null otherwise
      // group     should be null if user == null, null or not-null otherwise

      System.out.println("SimpleSampleLoginModule.commit");
      if (loginSucceeded) {
         subject.getPrincipals().addAll(principalsForSubject);
         principalsInSubject = true;
         return true;
      } else {
         return false;
      }
   }
   public boolean abort() throws LoginException 
   {
      // The abort method is called to abort the authentication process. This is
      // phase 2 of authentication when phase 1 fails. It is called if the
      // LoginContext's overall authentication failed.
      // loginSucceeded      should be true or false
      // user      should be null if !loginSucceeded, otherwise null or not-null
      // group     should be null if user == null, otherwise null or not-null
      // principalsInSubject      should be false if user is null, otherwise true 
      //                          or false

      System.out.println("SimpleSampleLoginModule.abort");
      if (principalsInSubject) {
         subject.getPrincipals().removeAll(principalsForSubject);
         principalsInSubject = false;
      }
      return true;
   }
   public boolean logout() throws LoginException 
   {
      // should never be called
      System.out.println("SimpleSampleLoginModule.logout");
      return true;
   }
   private void throwLoginException(String msg) throws LoginException
   {
      System.out.println("Throwing LoginException(" + msg + ")");
      throw new LoginException(msg);
   }
   private void throwFailedLoginException(String msg) throws FailedLoginException
   {
      System.out.println("Throwing FailedLoginException(" + msg + ")");
      throw new FailedLoginException(msg);
   }
   private Callback[] getCallbacks() throws LoginException
   {
      if (callbackHandler == null) {
         throwLoginException("No CallbackHandler Specified");
      }
      if (database == null) {
         throwLoginException("database not specified");
      }
      Callback[] callbacks;
      if (isIdentityAssertion) {
         callbacks = new Callback[1];
      } else {
         callbacks = new Callback[2];
         callbacks[1] = new PasswordCallback("password: ",false);
      }
      callbacks[0] = new NameCallback("username: ");
      try {
          callbackHandler.handle(callbacks);
      } catch (IOException e) {
         throw new LoginException(e.toString());
      } catch (UnsupportedCallbackException e) {
         throwLoginException(e.toString() + " " + e.getCallback().toString());
      }
      return callbacks;
   }
   private String getUserName(Callback[] callbacks) throws LoginException
   {
      String userName = ((NameCallback)callbacks[0]).getName();
      if (userName == null) {
         throwLoginException("Username not supplied.");
      }
      System.out.println("\tuserName\t= " + userName);
      return userName;
   }
   private void addGroupsForSubject(String userName)
   {
      for (Enumeration e = database.getUserGroups(userName);
         e.hasMoreElements();) {
            String groupName = (String)e.nextElement();
            System.out.println("\tgroupName\t= " + groupName);
            principalsForSubject.add(new WLSGroupImpl(groupName));
      }
   }
   private String getPasswordHave(String userName, Callback[] callbacks) throws 
   LoginException
   {
      PasswordCallback passwordCallback = (PasswordCallback)callbacks[1];
      char[] password = passwordCallback.getPassword();
      passwordCallback.clearPassword();
      if (password == null || password.length < 1) {
         throwLoginException("Authentication Failed: User " + userName + ".  
            Password not supplied");
      }
      String passwd = new String(password);
      System.out.println("\tpasswordHave\t= " + passwd);
      return passwd;
   }
}

管理コンソールによるカスタム認証プロバイダの構成

カスタム認証プロバイダを構成するということは、そのカスタム認証プロバイダをセキュリティ・レルムに追加するということです。追加されたカスタム認証プロバイダには、認証サービスを必要とするアプリケーションからアクセスできます。

カスタム・セキュリティ・プロバイダの構成は管理タスクですが、カスタム・セキュリティ・プロバイダの開発者が行うこともできます。この項では、カスタム認証プロバイダの構成担当者にとって重要な情報を提供します。

ユーザー・ロックアウトの管理

カスタム認証プロバイダを使用する一環として、ユーザー・ロックアウトを構成および管理する方法を検討する必要があります。以下の2つの選択肢があります。

レルム・ワイドのユーザー・ロックアウト・マネージャの使用

WebLogicセキュリティ・フレームワークは、WebLogicセキュリティ・フレームワークと直接連携してユーザー・ロックアウトを管理するレルム・ワイドのユーザー・ロックアウト・マネージャを提供します。

注意:

レルム・ワイドのユーザー・ロックアウト・マネージャとWebLogic Server 6.1 PasswordPolicyMBean(レルム・アダプタ・レベル)の両方をアクティブにできます。WebLogic Server APIリファレンス(Javadoc)を参照してください。

レルム・ワイドのユーザー・ロックアウト・マネージャを使用する場合、それをカスタム認証プロバイダと連携させるためには、WebLogic Server管理コンソールを使用して次のことを行います。

  1. ユーザー・ロック・アウトを有効にします。(デフォルトで有効にする必要があります。)

  2. 必要に応じてユーザー・ロックアウトのパラメータを修正します。

    注意:

    ユーザー・ロックアウト・マネージャへの変更は、サーバーを再起動するまで有効になりません。WebLogic Server管理コンソールを使用して前述のタスクを実行する手順は、Oracle WebLogic Serverセキュリティの管理のユーザー・アカウントの保護で説明されています。

独自のユーザー・ロックアウト・マネージャの実装

カスタム認証プロバイダの一部として独自のユーザー・ロックアウト・マネージャを実装する場合は、次の手順を行う必要があります。

  1. レルム・ワイドのユーザー・ロックアウト・マネージャを無効にして二重ロックアウトを防止します。(WebLogic Server管理コンソールを使用して新しいセキュリティ・レルムを作成すると、ユーザー・ロックアウト・マネージャが必ず作成されます。)このタスクを実行する手順は、Oracle WebLogic Serverセキュリティの管理のユーザー・アカウントの保護で説明されています。

  2. WebLogicセキュリティ・フレームワークのレルム・ワイドの実装からは何も借用できないので、以下のタスクを行うことも必要です。

    1. ユーザー・ロックアウト・マネージャの実装を提供します。ユーザー・ロックアウト・マネージャに関して、セキュリティ・サービス・プロバイダ・インタフェース(SSPI)は提供されません。

    2. ユーザー・ロックアウト・マネージャの管理に使用できるMBeanを変更します。

    3. 管理コンソールからユーザー・ロックアウト・マネージャを管理する場合、コンソール拡張を使用してWebLogic Server管理コンソールにユーザー・ロックアウト・マネージャを組み入れます。

認証プロバイダの順序の指定

「LoginModuleとマルチパート認証」で説明されているように、認証プロセスの結果は、複数の認証プロバイダ(その結果としてLoginModule)の構成順序によって影響を受けます。

認証プロバイダは任意の順序で構成できます。ただし、構成済の認証プロバイダの順序を変更する必要がある場合は、Oracle WebLogic Serverセキュリティの管理の認証プロバイダの順序の変更で説明されている手順に従ってください。