Oracle® Fusion Middleware

Oracle Unified Directory開発者ガイド

11g リリース2 (11.1.2)

E50140-03(原本部品番号:E38455-04)

2014年4月

Oracle Unified Directory機能を拡張するソフトウェア・プラグインの作成およびデプロイに関する情報を提供します。

Oracle Fusion Middleware Oracle Unified Directory開発者ガイド, 11g リリース2 (11.1.2)

E50140-03

Copyright © 2013, 2014, Oracle and/or its affiliates. All rights reserved.

原本著者:  Gina Cariaga

原本協力著者:  Cyril Tissot、Sylvain Duloutre

原本協力者:  Etienne Remillion、Jerome Arnou、Sebastien Bertholet

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクル社までご連絡ください。

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations. As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs. No other rights are granted to the U.S. Government.

このソフトウェアもしくはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアもしくはハードウェアは、危険が伴うアプリケーション(人的傷害を発生させる可能性があるアプリケーションを含む)への用途を目的として開発されていません。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用する際、安全に使用するために、適切な安全装置、バックアップ、冗長性(redundancy)、その他の対策を講じることは使用者の責任となります。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、オラクル社およびその関連会社は一切の責任を負いかねます。

OracleおよびJavaはOracle Corporationおよびその関連企業の登録商標です。その他の名称は、それぞれの所有者の商標または登録商標です。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXは、The Open Groupの登録商標です。

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。オラクル社およびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。オラクル社およびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。

目次

タイトルおよび著作権情報

はじめに

- 対象読者

- ドキュメントのアクセシビリティについて

- 関連ドキュメント

- 表記規則

1 Oracle Unified Directoryプラグインの基本コンセプトの理解

- 1.1 OUDプラグインの実装の要否判定

- 1.2 OUDプラグインおよびOUDワークフロー

- 1.3 OUDプラグインの実装ポイント

- 1.4 Oracle Unified Directoryプラグインのバージョン情報

2 OUDプラグインの作成とデプロイ

- 2.1 始める前に

- 2.2 プラグインをOUDインスタンスにデプロイする手順

3 OUDプラグインAPIリファレンスの使用

- 3.1 OUDプラグイン構成

- 3.1.1 OUDプラグイン構成の格納

- 3.1.2 OUDプラグイン構成の取得

- 3.1.3 プラグイン・プロパティの自動化パーサーの作成

- 3.1.4 OUDプラグイン構成の動的変更

- 3.1.5 プラグイン構成の検証

- 3.2 リクエストの処理

- 3.2.1 リクエストの変更

- 3.2.2 リクエストのラッピング

- 3.2.3 リクエストの転送

- 3.2.4 結果を返す

- 3.3 レスポンスの処理

- 3.4 結果の処理

- 3.4.1 結果の無視

- 3.4.2 検索エラーのインターセプト

- 3.4.3 返されたエントリのカウント

- 3.5 フィルタ処理

- 3.6 内部操作

- 3.6.1 内部リクエストの作成

- 3.6.2 内部リクエストの起動

- 3.6.2.1 モード1

- 3.6.2.2 モード2

- 3.7 エラー処理

- 3.8 ロギングとデバッグ

- 3.8.1 クライアント・リクエストの処理中にプラグインをデバッグする手順

- 3.8.2 プラグイン初期化のデバッグの手順

はじめに

『Oracle Fusion Middleware Oracle Unified Directory開発者ガイド』では、Oracle Unified DirectoryプラグインAPIを使用してプログラムでOUD機能を拡張する方法について説明します。

対象読者

このガイドは、Oracle Unified Directoryの使用に熟練したソフトウェア開発者を対象としています。

ドキュメントのアクセシビリティについて

Oracleのアクセシビリティについての詳細情報は、Oracle Accessibility ProgramのWebサイト(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=docacc)を参照してください。

Oracle Supportへのアクセス

Oracleサポート・サービスでは、My Oracle Supportを通して電子支援サービスを提供しています。詳細情報は(http://www.oracle.com/pls/topic/lookup?ctx=acc&id=info) か、聴覚に障害のあるお客様は (http://www.oracle.com/pls/topic/lookup?ctx=acc&id=trs)を参照してください。

関連ドキュメント

詳細は、Oracle Unified Directory 11gリリース1.1.2のドキュメント・セットに含まれる次のドキュメントを参照してください。

- Oracle Fusion Middleware Oracle Unified Directoryリリース・ノート

- Oracle Fusion Middleware Oracle Unified Directoryインストレーション・ガイド

- Oracle Fusion Middleware Oracle Unified Directory構成リファレンス

- Oracle Fusion Middleware Oracle Unified Directory管理者ガイド

- Oracle Fusion Middleware Oracle Unified Directory Java APIリファレンス

表記規則

このマニュアルでは次の表記規則を使用します。

規則

意味

太字

太字は、操作に関連するGraphical User Interface要素、または本文中で定義されている用語および用語集に記載されている用語を示します。

イタリック体

イタリックは、ユーザーが特定の値を指定するプレースホルダ変数を示します。

固定幅フォント

固定幅フォントは、段落内のコマンド、URL、サンプル内のコード、画面に表示されるテキスト、または入力するテキストを示します。

1 Oracle Unified Directoryプラグインの基本コンセプトの理解

この章では、次の内容を説明します。

- 第1.1項「OUDプラグインの実装の要否判定」

- 第1.2項「OUDプラグインおよびOUDワークフロー」

- 第1.3項「OUDプラグインの実装ポイント」

- 第1.4項「Oracle Unified Directoryプラグインのバージョン情報」

1.1 OUDプラグインの実装の要否判定

Oracle Unified Directory (OUD)プラグインAPIは、既存のディレクトリ・サーバー機能を拡張する手段を提供しています。非常に特有なディレクトリ・サーバー要件があってOUDではそのままでは対応できない場合、プラグインを開発することもできます。たとえば、OUDプラグインを使用して次のことを正常に実現できました。

- LDAPエラー・コードおよびエラー・メッセージの書込み

- オンデマンドのパスワード移行

- 複数のパスワード・タイプを使用した認証

- ユーザー・エントリの基準に基づいた操作ルーティング

これらのプラグインのいくつかは、Oracle顧客のOUDへのシームレスな移行を支援する役割を果たしました。これらは、LDAP操作をカスタマイズして結果をプログラムにより操作することでディレクトリ・サーバー機能をどのように拡張できるかの例にすぎません。

独自のOUDプラグインを開発することの利点と費用を分析する際には、次の点を考慮してください。

- ディレクトリのデプロイメントにおける潜在的な障害ポイントを最小にするために、独自のOUDプラグインの開発は、既存のOUD機能やその組合せでも希望する結果を実現できない場合にのみ行う必要があります。

- 新しいリリースにアップグレードする際は、進化している可能性がある新しいOUD機能を踏まえて、使用中のカスタム・プラグインにまだ意味があるかどうかを判断する必要があります。さらに、使用中のプラグインがOUDの新しいリリースとの下位または上位互換性を確保できるようにアップグレードする必要があります。

1.2 OUDプラグインおよびOUDワークフロー

OUDプラグインは新しいタイプのOUDワークフロー要素と考えることができます。ワークフローおよびワークフロー要素はOUDディレクトリにおける基礎的なビルディング・ブロックです。ワークフローおよびワークフロー要素がOracle Unified Directoryアーキテクチャでどのように機能するかの詳細は、『Oracle Fusion Middleware Oracle Unified Directory管理者ガイド』を参照してください。

OUDプラグインは任意のワークフロー要素ツリーに挿入できます。OUDプラグインがワークフロー要素ツリー内で実行できる代表的なタスクは次のとおりです。

- チェーン内の前のワークフロー要素からのLDAPリクエストをインターセプトし、それらを変更するか拡張するかの選択肢を確保します。

- LDAPエントリおよびチェーン内の次のワークフロー要素からの結果をインターセプトします。

- OUDとともに提供される即時利用可能なその他のワークフロー要素を保管し活用します。

- LDAPリクエストを受け取ったときおよびワークフローによるルーティング決定後にプラグインを起動します。

次の図に、ネーミング・コンテキスト・ワークフローおよびDNリネーム・ワークフロー要素を含む代表的なOUDワークフローを示します。OUDプラグインがこれらのビルディング・ブロックの下流、およびリモート・バックエンド・ワークフロー要素の上流に挿入されます。

いくつかのOUDプラグインを開発した後に、OUDワークフロー内にプラグイン・チェーンを形成できます。

1.3 OUDプラグインの実装ポイント

OUDプラグインは次の実装ポイント・セットを経由してOUDコア・サーバーと対話します。

- 管理プラグイン管理: 起動、停止、ステータスおよび構成の変更

- LDAP操作処理

- リクエストのログ記録、およびプラグインAPIにより操作されるオブジェクトのインスタンス作成に使用される、プラグインとコア・ディレクトリ・サーバー間のメイン・インタフェースであるコンテキスト

プラグインを管理するための実装ポイントはoracle.oud.plugin.ManagedPluginインタフェースに定義されています。

- initializePlugin()メソッドはプラグインがサーバー起動時に初期化される際に起動されます。

- finalizePlugin()メソッドはプラグインが停止される際に起動されます。

- handleConfigurationChange()メソッドはプラグイン構成が変更される際に常に起動されます。第3.1.4項「OUDプラグイン構成の動的変更」も参照してください。

LDAP操作をインターセプトするための実装ポイントは、oracle.oud.plugin.RequestManagerインタフェースに定義されています。第3.6項「内部操作」も参照してください。

1.4 Oracle Unified Directoryプラグインのバージョン情報

Oracle Unified Directoryプラグインが、次の3つのJavaインタフェース: oracle.oud.RequestManager、oracle.oud.plugin.Pluginおよびoracle.oud.plugin.ManagedPluginから形成されるoracle.oud.plugin.ManagedPluginの実装です。

oracle.oud.RequestManager

LDAPプロトコルで定義されている各タイプの操作のメソッドを定義します。handleAddという名前のメソッドは、プラグインがLDAPのadd操作に含まれるたびに呼び出されます。bind、compare、delete、modify、modifyDNおよびsearch操作には、同様のメソッドが存在します。例外は、abandonおよびunbind操作で、これらの2つのタイプのリクエストはインターセプトできません。

oracle.oud.plugin.Plugin

名前をインスタンスごとに一意のプラグインに関連付けます。プラグインを識別すると、受け取ったリクエストをプラグインが複数のプラグインの中の特定のプラグインにルーティングする際に役立ちます。

oracle.oud.plugin.ManagedPlugin

プラグインのライフ・サイクルを定義します。ライフ・サイクルは、サーバーが起動したときまたはプラグインが作成されたときのプラグインの初期化から始まります。初期化後、プラグインは構成変更を受け取ることができます。サーバーが停止したときまたはプラグインがサーバー構成から削除されたときに、プラグインはファイナライズされます。

OUDプラグインの後にプロセス・チェーンの1つ以上のプラグインを続けることができます。最も一般的なケースは、後にプラグインが1つのみ続いているOUDプラグインです。このタイプのプラグインは、リクエストを受け取り、受け取ったリクエストのロギングまたは変更などの追加アクションを実行した後、そのリクエストを次のプラグインに転送できます。LDAP操作で応答が返されたときに、同様のアクションを実行できます。

プロセス・チェーンに後続のプラグインがないプラグインが、LDAPリクエストで操作されるエントリの格納を受け持ちます。格納はローカルでもリモートでも可能です。どちらの場合も、プラグインは受け取ったLDAPリクエストの結果の割当てを受け持ちます。

プロセス・チェーンで複数のプラグインが続いているプラグインが最も難しいケースです。このタイプのプラグインは、分散またはロード・バランシングを含む複雑なアーキテクチャにのみ使用されます。たとえば、このタイプのプラグインは専用プラグイン上のバインド・リクエストをルーティングしたり、他のプラグイン上の他のLDAP操作をルーティングするために使用される場合があります。

OUDプラグインAPIには、抽象クラスoracle.oud.plugin.AbstractPluginであるoracle.oud.plugin.ManagedPlugin Javaインタフェースのデフォルトの実装が提供されています。このクラスでは、受け取ったリクエストを処理チェーン内のその次のプラグインに転送する以外に何もアクションを実行しないプラグインの実装が提供されています。デフォルトの実装では、プラグインに少なくとも1つ後続プラグインがあることを前提としています。ただし、必要であれば適切なメソッドを上書きしてデフォルトの動作を変更できます。oracle.oud.plugin.AbstractPluginクラスから派生したプラグイン実装を作成する必要があります。これにより、実装されたJavaインタフェースが変更された場合の下位互換性が最適化されます。

2 OUDプラグインの作成とデプロイ

この章では、アクションを実行しないOracle Unified Directory (OUD)プラグインを作成およびデプロイする方法について説明します。この章では、次の内容を説明します。

- 第2.1項「始める前に」

- 第2.2項「プラグインをOUDインスタンスにデプロイする手順」

2.1 始める前に

次のタスクを完了して開発環境を準備します。

- Oracle Unified Directoryをインストールし、生成された50個のエントリを持つ新しいインスタンスを作成します。

- Oracle Unified Directoryインスタンスで稼働しているまったく同じバージョンのJava Runtime Environmentを持つJava Development Kitをインストールします。

- 好みの統合開発環境(IDE)を使用してプラグイン開発用の新しいプロジェクトを作成し、install-dir/OracleUnifiedDirectory/lib/oud.jarにあるJARファイルoud.jarを参照します

2.2 プラグインをOUDインスタンスにデプロイする手順

1. oracle.oud.plugin.AbstractPluginクラスを拡張するクラスを新規作成します。このクラスは何もアクションを実行しませんが、処理の一部になります。例:

package oracle.oud.example;
import oracle.oud.plugin.AbstractPlugin;
/**
* A plug-in that does not perform any action.
*/
public class ExamplePlugin
extends AbstractPlugin
{

}

2. プラグイン・プロジェクトを作成します。
生成されたプラグインJARファイルには次のファイルが含まれている必要があります。

- META-INF/MANIFEST.MF

- oracle/oud/example/ExamplePlugin.class

3. プラグインが以降のリリースのOUDプラグインAPIでも引き続き機能できるように、作成されたJARファイルに特定のバージョニング・ファイルを埋め込むことができます。埋め込むファイルの名前はplugin.propertiesです。
plugin.propertiesファイルを次のように変更します。

1. JARファイルに含まれるすべてのプラグインのターゲット・バージョンを定義する手順は次のとおりです。
plugin.version=11.1.2.1.0

2. ExamplePluginプラグインのみのターゲット・バージョンを定義するには次のように指定します。
plugin.ExamplePlugin.version=11.1.2.1.0

plugin.propertiesファイルが存在しない場合、現在の実装のプラグインAPIの動作が適用されます。

4. Oracle Unified Directoryインスタンスを再起動してJARファイルの変更を有効にします。

1. OUDインスタンスを停止します。

UNIX、Linux

$ cd instance-directory/OUD/bin
$ stop-ds

Windows

C:\> cd instance-directory\OUD\bat
C:\> stop-ds

2. プラグインJARファイルをlibディレクトリにコピーします。

UNIX、Linux

# cp plugin.jar lib

Windows

C:\> copy plugin.jar lib

3. OUDインスタンスを再起動します。

UNIX、Linux

# start-ds

Windows

C:\> start-ds

5. プラグインがサーバー処理の一部となるようにサーバー構成を変更します。
dsconfigコマンドを使用してプラグインをOUDサーバーのワークフロー要素として宣言します。次の情報を指定する必要があります。

- このプラグイン・インスタンスを一意に識別するプラグイン名(サンプル中のExamplePlugin)

- oracle.oud.plugin.ManagedPlugin Javaインタフェースを実装するJavaクラスの名前

- プラグインを有効にするか無効にするか

- 挿入するプラグインの後にあるワークフロー要素の名前。
プラグインには、実装するユース・ケースにより0、1個またはそれよりも多くのワークフロー要素が続く場合があります。例:

# dsconfig create-workflow-element \
--set enabled:true \
--set plugin-class:oracle.oud.example.ExamplePlugin \
--set next-workflow-elements:userRoot \
--type plug-in \
--element-name ExamplePlugin

プラグインを作成した後、プラグイン・ワークフロー要素をワークフロー内に挿入します。プラグイン・ワークフロー要素は、ワークフローの次の要素、または既存のワークフロー要素の次の要素としてプラグイン・クラスを指定する必要があります。次のコマンドは、ワークフローuserRoot0の構成を、LDAPリクエストが以前に追加されたサンプル・プラグインに転送されるように変更します。

# dsconfig set-workflow-prop \
--workflow-name userRoot0 \
--set workflow-element:ExamplePlugin

同じプラグイン実装の複数のインスタンスをそれぞれが一意の名前を持つように作成できます。

3 OUDプラグインAPIリファレンスの使用

Oracle Unified Directory (OUD)のJavaクラス、メソッドおよび関連する構文と使用方法の詳細は、Oracle Unified Directory Java APIリファレンスを参照してください。この章では、OUDプラグインAPIの使用に関する一般情報について説明します。

この章は次の項で構成されています。

- 第3.1項「OUDプラグイン構成」

- 第3.2項「リクエストの処理」

- 第3.3項「レスポンスの処理」

- 第3.4項「結果の処理」

- 第3.5項「フィルタ処理」

- 第3.6項「内部操作」

- 第3.7項「エラー処理」

- 第3.8項「ロギングとデバッグ」

3.1 OUDプラグイン構成

OUDプラグインAPIには、プラグイン構成を格納、取得、変更および検証するための便利な方法が提供されています。

3.1.1 OUDプラグイン構成の格納

OUDでは、プラグイン構成がプラグイン構成エントリの一部として格納されます。構成要素はOUDのconfig.ldifファイルにキーと値のペアとして格納されます。分かりやすくするために、このメカニズムを使用してください。ただし、OUDプラグイン・アーキテクチャを使用すると、外部ファイルなどの代替方法を使用して構成を取得できます。

プラグイン構成は、デフォルトの構成モデルでキーと値のペアのセットとして表されます。キーと値はOUDサーバーおよびdsconfigコマンド行ツールでRaw文字列として処理されます。キーと値のペアはdsconfigツールとプラグイン・ワークフロー要素に関連付けられたplugin-propertiesプロパティを使用して設定できます。

例3-1に、プラグイン・プロパティを追加する方法を示します。

例3-1 プラグイン・プロパティの追加

dsconfig set-workflow-element-prop \
--element-name ExamplePlugin \
--add plugin-properties:customProperty=localDB1 \
--hostname host1 \
--port 4444 \
--trustStorePath install-dir/OUD/config/admin-truststore \
--bindDN cn=Directory\ Manager \
--bindPasswordFile ****** \
--no-prompt

例3-2では、プラグインExamplePluginはcustomPropertyという名前のカスタム・プロパティを使用して構成されています。このプロパティは汎用のplugin-propertiesパラメータの値として指定されます。

例3-2 カスタム・プロパティの構成

$dsconfig get-workflow-element-prop --element-name ExamplePlugin

Property : Value(s)
----------------------:-------------------------------------------------------
enabled : true
next-workflow-elements : localDB1
plugin-class : oracle.oud.plugin.example.ExamplePlugin
plugin-properties : customProperty=localDB1

3.1.2 OUDプラグイン構成の取得

OUDプラグイン構成は、プラグインの初期化中に提供されるPluginConfigurationインスタンスから入手できます。これは、例3-3に示されているようにinitializePluginメソッドをオーバーライドすることでアクセスできます。

例3-3 OUDプラグイン構成にアクセスするためのinitializePluginのオーバーライド

@Override
public void initializePlugin(PluginConfiguration configuration,PluginContext context) throws PluginException
{

// Plugin configuration as a Set of properties
Set<String> properties = configuration.getProperties();

String aParameter=null;

for(String value: properties)
{
if ( value.startsWith("customProperty=") )
{
aParameter = value.substring(value.indexOf("=")+1);
break;
}
}

// Expected property not found
if ( aParameter == null )
{
throw new PluginException
(context.getTypeBuilder().newMessage("customProperty missing in configuration."));
}

// Either use the configuration right now or make it persistent using class members.
}

この例で、構成はraw構成オブジェクトからプロパティのセットとして取得されます。読み込まれたプロパティはすぐに使用することも、将来プラグインを実装するJavaクラスのメンバーで使用するために格納することもできます。

3.1.3 プラグイン・プロパティの自動化パーサーの作成

OUDにはプラグイン構成を取得するための代替方法が提供されています。

プラグイン・プロパティの自動化パーサーを作成する手順は次のとおりです。

1. クラスoracle.oud.plugin.PluginConfigurationを拡張するJavaインタフェースを作成します。

2. 取得が必要なプロパティごとに、get<property-name>()の書式のゲッターを追加します。property-nameは、プラグイン・プロパティに定義されているキーと値のペアのキーと一致する必要があります。名前の大小文字は無視されます。

3. 返されるメソッド・タイプは、valueOf(String) - java.lang.String.valueOf(String)がこのアサーションと一致する静的メソッドを提供するクラスである必要があります。
プラグイン・プロパティcustomPropertyを解析するJavaインタフェースは例3-4のようになります。

例3-4 プラグイン・プロパティの解析

public interface PropertyConfiguration
extends oracle.oud.plugin.PluginConfiguration
{
/**
* Return the value associated to the key 'customProperty'.
*
* @return the value associated to the key 'customProperty'.
*/
String getCustomProperty();
}

その後、プラグインの初期化を次の例に示されているように上書きできます。

@Override
public void initializePlugin(final PluginConfiguration configuration,
final PluginContext context)
throws PluginException
{
super.initializePlugin(configuration, context);

PropertyConfiguration propertyConfiguration = this.getConfiguration(PropertyConfiguration.class);

String customProperty = propertyConfiguration.getCustomProperty();
// Perform check...
}

3.1.4 OUDプラグイン構成の動的変更

プラグイン構成に対する変更は、メソッドhandleConfigurationChange()をオーバーライドすることで動的にキャッチできます。新しい構成は例3-5に示されているように取得できます。

例3-5 変更されたプラグイン構成の取得

@Override
public void handleConfigurationChange(final PluginConfiguration configuration)
throws PluginException
{

// The new configuration is stored in the configuration object
// parse again the plugin configuration
String aParameter;
Set<String> properties = configuration.getProperties();

for(String value: properties)
{
if ( value.startsWith("customProperty=") )
{
aParameter = value.substring(value.indexOf("=")+1);
break;
}
}
}

handleConfigurationChange()メソッドは、OUDサーバーにより管理されているプラグイン・プロパティの更新時にのみ起動されます。構成を外部ファイルに格納するように決定した場合、ファイル・コンテンツに対する変更はここで説明したメカニズムでは動的に検出されません。

3.1.5 プラグイン構成の検証

dsconfigツールは、カスタム・プラグイン構成のプロパティに関する構文ケースを作成しません。そのため、このプラグインは起動時または構成の動的変更時に構成の検証が必要です。プラグイン・コードは、無効な構成から復旧できないときにPluginExceptionを発生させる必要があります。

プラグインは、プラグインの初期化中にPluginExceptionが発生したときに自動的に無効にされます。無効な動的構成変更は、handleConfigurationChange()メソッドでPluginExceptionを発生させることで拒否できます。

3.2 リクエストの処理

プラグインは、oracle.oud.RequestManagerインタフェースによって定義された対応するコールバックを実装することで、OUDサーバーで処理された任意のLDAPリクエストをインターセプトできます。各タイプのLDAP操作がハンドラ・メソッドに対応しています。たとえばadd操作はhandleAdd()メソッドによって管理される、というように順に対応しています。

受け取ったLDAPリクエストはサーバーによって処理されます。このように、リクエストのプロパティを変更することでパフォーマンス、整合性およびセキュリティに関してサーバーに影響を及ぼすことができます。

LDAPリクエストに含まれる各プロパティをゲッターで取得し、セッターで変更できます。

各ハンドラは、関連付けられた3つのパラメータをとります。

- このプラグインの前のワークフロー要素によって提供されたとおりのすべてのリクエスト・プロパティを含むLDAPリクエスト

- 前のワークフロー要素(一度処理されたLDAPリクエストの結果)に戻るために使用する参照である結果ハンドラ

- サーバーの各種要素(ロギング・サブシステム、プラグインAPIオブジェクトの作成、クライアント接続、リクエストの破棄など)へのアクセスを提供するツールボックス参照であるコンテキスト

bindリクエストは4つ目のパラメータをとりますが、これはLDAPプロトコルのバージョンであり便宜上の目的でのみ提供されています。abandonおよびunbindメソッドはインターセプトできません。リクエストのabandonはリクエストのコンテキストを使用して検出できます。unbind操作は、クライアント接続がサーバーから切断されることを意味します。

プロセス・チェーン内の各プラグインに配慮する必要がある規定は、LDAPリクエストを受け取ったときの状態のまま返すことです。これはリクエスト・ハンドラのすべての実装に適用されます。これはプラグインで実行される最も重要な事項です。これが重要な理由は、リクエストにすでに結果があってもリクエストが完了していない場合があるためです。

次の例を検討してください: プラグインはロードバランサ後に実行される処理の一部です。リクエストを変更し、受け取った状態でリクエストを返すかわりに変更されたリクエストを返すと、ロードバランサが正しく機能しない場合があります。実際に、このリクエストは最初のルートで変更され、最初のルートが失敗した場合は2番目のルートで再実行されて変更される可能性があります。

要約すると、リクエストは受け取ったときとまったく同じ形で発行する必要があることに注意してください。

3.2.1 リクエストの変更

次の例では、検索リクエストの有効範囲が変更されます。検索の有効範囲はBASE_OBJECTに変更され、検索リクエストが処理されたときに復元されます。

1. 検索リクエストをインターセプトするには、サンプルのプラグインのhandleSearch(...)メソッドをオーバーライドします。例3-6を参照してください。

例3-6 検索リクエストをインターセプトするためのhandleSearch(...)のオーバーライド

@Override
public void handleSearch(final RequestContext requestContext,
final SearchRequest request,
final SearchResultHandler resultHandler)
throws UnsupportedOperationException {

System.out.println("plug-in: search received " + request);

// Store the received search scope.
SearchScope scopeReceived = request.getScope();

// Set a base search scope for all search requests
request.setScope(SearchScope.BASE_OBJECT);

System.out.println("plug-in: search modified " + request);

// Forward the request to the next plug-in.
this.getConfiguration()
.getFirstNextPlugin()
.handleSearch(requestContext,
request,
resultHandler);

// Restore the original value to give the request back as received.
request.setScope(scopeReceived);
}

2. Oracle Unified Directoryインスタンスを再起動してJARファイルの変更を有効にします。

1. OUDインスタンスを停止します。

UNIX、Linux

$ cd instance-directory/OUD/bin
$ stop-ds

Windows

C:\> cd instance-directory\OUD\bat
C:\> stop-ds

2. プラグインJARファイルをlibディレクトリにコピーします。

UNIX、Linux

# cp plugin.jar lib

Windows

C:\> copy plugin.jar lib

3. OUDインスタンスを再起動します。

UNIX、Linux

# start-ds

Windows

C:\> start-ds

3. 次のコマンドを実行します。

UNIX、Linux

$ ldapsearch --hostname localhost --port 1389 --bindDN "cn=directory manager" --bindPasswordFile /tmp/password --searchScope sub --baseDN "uid=user.1,ou=people,dc=example,dc=com" "(objectclass=*)"

Windows

C:\ ldapsearch --hostname localhost --port 1389 --bindDN "cn=directory manager" --bindPasswordFile C:\tmp\password --searchScope sub --baseDN "uid=user.1,ou=people,dc=example,dc=com" "(objectclass=*)"

4. 各コマンドごとに、ログ・ファイル
(UNIXまたはLinuxではinstance-dir/OUD/logs/server.out、Windowsではinstance-dir\OUD\logs\server.out)
に次のような情報を含む必要があります。

plug-in: search received SearchRequest(name=uid=user.1,ou=people,dc=example,dc=com, scope=sub, dereferenceAliasesPolicy=never, sizeLimit=0, timeLimit=0, typesOnly=false, filter=(objectClass=*), attributes=[], controls=[])
plug-in: search modified SearchRequest(name=uid=user.1,ou=people,dc=example,dc=com, scope=base, dereferenceAliasesPolicy=never, sizeLimit=0, timeLimit=0, typesOnly=false, filter=(objectClass=*), attributes=[], controls=[])

注意:

リクエストは、呼出しにより次のプラグインに渡されます。

this.getConfiguration().getFirstNextPlugin().handleSearch(...)

これはまさしくAbstractPluginのデフォルトの実装により実行されることです。次を呼び出すことで同じことを実現できます。

super.handleSearch(...)

3.2.2 リクエストのラッピング

リクエストの代替変更方法は、元のリクエストをラッパーという名前の特殊なオブジェクトにラッピングすることです。リクエスト・ラッパーは、ラッピングするリクエストとまったく同じJavaインタフェースを提供する実装で、メソッド上で実行されるすべての呼出しをラッピングされたリクエストに転送します。

プロパティの値を変更するには、該当するメソッドをオーバーライドします。例3-7に、検索リクエストの有効範囲を変更する方法を示します。

例3-7 検索結果の有効範囲の変更

@Override
public void handleSearch(final RequestContext requestContext,
final SearchRequest request,
final SearchResultHandler resultHandler)
throws UnsupportedOperationException {

SearchRequest newRequest = new SearchRequestWrapper(request)
{
@Override
public SearchScope getScope()
{
// Change the scope of this request.
return SearchScope.BASE_OBJECT;
}
};

// Forward the request to the next plug-in.
this.getConfiguration()
.getFirstNextPlugin()
.handleSearch(requestContext,
newRequest,
resultHandler);
}

この代替方法にはラッピングされたリクエストがそのまま残るという利点があります。このように、有効範囲プロパティは変更されなかったため復元する必要はありません。

ただし、この代替方法を使用する場合、問題が発生することがあります。ラッピングされたリクエストは、そのアウトバウンドのラッパーについて認識していません。処理がラッパー・リクエストのレベルで実行される場合で、この処理にラッパーのレベルで再定義されたプロパティが含まれている場合、それらのプロパティは無視されます。ラッピングされたリクエストは、それ自身のプロパティに対してのみアクセス権があります。

ラッパーはpackage oracle.oud.requestsのすべてのタイプのリクエストに対して提供されます。

3.2.3 リクエストの転送

多くの場合、プラグインはリクエストをインターセプトし、なんらかの処理を実行してからチェーン内の次のワークフローにリクエストを転送します。非常に多くの場合で、次のワークフロー要素は正確に1つのみ存在します。この場合、リクエストはスーパー・インスタンスの対応するメソッドを起動することで次の要素に渡すことができます。

リーフ・プラグインの場合、oracle.oud.AbstractPluginにより実装されるすべてのリクエスト・ハンドラをオーバーライドする必要があり、リクエストが次の項で説明されているようにして返される必要があります。

一部の特殊なケースでは、プラグインの後にワークフロー要素がいくつか続く場合があります。プラグインの実装は、どのワークフロー要素にリクエストを転送するかを判断する必要があります。次のワークフロー要素の一覧は、PluginConfigurationインスタンスからgetNextPlugins()メソッドまで取得できます。その後、例3-8に示されているように、適切なメソッドを直接起動することでリクエストが適切なワークフロー要素に転送されます。

例3-8 リクエストの転送

@Override
public void handleBind(final RequestContext requestContext,
final int version,
final BindRequest request,
ResultHandler resultHandler)
throws UnsupportedOperationException
{

// Get the original bind DN from the bind request
DN originalDn = request.getName();

// Transform the bind DN according to custom algorithm
DN newDn = transformDN(originalDn);

BindRequestWrapper wrapper = new BindRequestWrapper(request);

// Update the wrapper object
wrapper.setName(newDn);

// Retrieve the list of next plugins and figure out which one to use
List<Plugin> nextPlugins = this.getConfiguration().getNextPlugins();

// Pass the request to the appropriate plugin (assume the first one here)
nextPlugins.get(0).handleBind(requestContext,
version,
wrapper,
resultHandler);

}

3.2.4 結果を返す

場合によっては、プラグインがリクエストをインターセプトし、チェーン内の次のワークフロー要素にリクエストを転送するかわりに自分自身で結果を返すことができます。

結果オブジェクト・インスタンスは、oracle.oud.plugin.PluginContext.TypeBuilderクラスのnewResult()メソッドを使用して作成できます。その後、この結果は、ハンドラ・メソッドの引数として渡されたresultHandlerオブジェクトからhandleResult()またはhandleErrorResult()メソッドを呼び出すことでプラグインの呼出し元に返すことができます。例3-9に、bindリクエストをインターセプトしてInvalid Credentialsエラーを返す方法を示します。

例3-9 バインド・リクエストのインターセプトおよび無効な資格証明エラーの戻し

@Override
public void handleBind(final RequestContext requestContext,
final int version,
final BindRequest request,
ResultHandler resultHandler)
throws UnsupportedOperationException
{

// Get the original bind DN from the bind request
DN originalDn = request.getName();

// Apply custom logic to decide whether access is granted or not
// Assume invalid credentials

// Create a Result object
Result error = getPluginContext().getTypeBuilder().newResult(ResultCode.INVALID_CREDENTIALS);

// Return it to the plugin caller
resultHandler.handleErrorResult(error);

}

同様に、LDAPエントリをoracle.oud.plugin.PluginContext.TypeBuilderクラスのnewSearchResultEntry()メソッドを使用して作成できます。その後、このエントリは、handleSearch()メソッドの引数として渡されたsearchResultHandlerオブジェクトからhandleSearchResultEntry()またはhandleErrorResult()メソッドを起動することでプラグインの呼出し元に返すことができます。

3.3 レスポンスの処理

レスポンスをインターセプトする必要があるプラグインは、次のワークフロー要素にリクエストを発行する前に独自のResultHandlerインスタンスを提供することで対象を明示的に登録する必要があります。ResultHandlerのhandleResult()メソッドは、引数で渡された対応するResultインスタンスで操作が成功したときに起動されます。逆に、ResultHandlerのhandleErrorResult()はエラーが発生したときに起動されます。

カスタムのResultHandler実装で結果を調べて変更できますが、元のErrorHandlerの適切なメソッド(handleResult()またはhandleErrorResult())を起動して呼出し元のワークフロー要素に結果を渡す責任があります。分かりやすくするために、カスタムのResultHandlerをDefaultResultHandler objectclassの特殊化として実装してください。デフォルトでは、結果とエラーはチェーン内の上流のワークフロー要素に渡され、該当するメソッドのみをプラグイン実装によってオーバーライドする必要があります。

同様に、最終検索結果および検索エントリの両方をインターセプトするには検索操作にSearchResultHandlerを使用する必要があります。handleEntry()メソッドは、次のワークフロー要素によってLDAPエントリが返されるたびに起動されます。カスタムのSearchResultHandler実装は、元のSearchResultHandlerのhandleEntry()メソッドを起動してエントリをチェーンに送信する必要があります。

例3-10で、プラグインはバインド・エラーのみをインターセプトします。

例3-10 バインド・エラーのインターセプト

@Override
public void handleBind(final RequestContext requestContext,
final int version,
final BindRequest request,
ResultHandler resultHandler)
throws UnsupportedOperationException
{

// Create a new ResultHandler to intercept bind result
CustomResultHandler customBindHandler = new CustomResultHandler(resultHandler);

// Pass the request to the next plug-in with the custom ResultHandler
super.handleBind(requestContext,
version,
request,
customBindHandler);

}

// implementation of a custom ResultHandler to intercept errors

private class CustomResultHandler
extends DefaultResultHandler
{

public CustomResultHandler(ResultHandler resultHandler)
{
super(resultHandler);
}

@Override
public void handleErrorResult(Result error)
{

// Invoked when Bind fails
// Examine the result and implement some logic
// Pass the result up the chain

super.handleErrorResult(error);
}

}

例3-11では検索エントリと最終検索結果をインターセプトします。

例3-11 検索エントリと最終検索結果のインターセプト

@Override
public void handleSearch(final RequestContext requestContext,
final SearchRequest request,
SearchResultHandler resultHandler)
throws UnsupportedOperationException
{

// Create a new SearchResultHandler to intercept search entries
// and result
CustomSearchResultHandler customHandler = new CustomSearchResultHandler(resultHandler);

// Pass the request to the next plug-in with the custom ResultHandler
super.handleSearch(requestContext,
request,
customHandler);
}

// implementation of a custom SearchResultHandler to intercept entries and errors
private class CustomSearchResultHandler
extends DefaultSearchResultHandler

{
public CustomSearchResultHandler(SearchResultHandler resultHandler)
{
super(resultHandler);
}

@Override
public void handleErrorResult(Result error)
{
// Invoked when Search fails
// Examine the result and implement some logic
// Pass the result up the chain
super.handleErrorResult(error);
}

@Override
public void handleResult(Result result)
{
// Invoked when Search complete
// Examine the result and implement some logic
// Pass the result up the chain
super.handleResult(result);
}

@Override
public boolean handleEntry(SearchResultEntry entry)
{
// Invoked for every search entry to be returned
// Examine the result and implement some logic
// Pass the entry up the chain
return super.handleEntry(entry);
}
}

3.4 結果の処理

リクエスト結果が結果ハンドラと呼ばれるオブジェクトを使用して返されます。すべてのLDAP操作が、検索操作を除いて同じ種類の結果を共有します。検索操作にはエントリおよび参照である追加の結果が含まれます。LDAP操作は、リクエストと結果ハンドラのペアで構成されます。リクエストは、リクエストのプロパティにアクセスするために使用します。結果ハンドラは、処理されたリクエストの結果を前のプラグインにポストするために使用します。

3.4.1 結果の無視

例3-12で、前のプラグインにより提供された結果ハンドラは次のプラグインに直接渡されます。その結果、次のプラグインにより返される結果は次のプラグインから前のプラグインに、プラグイン自身をスキップして直接渡されます。リクエストが処理されたことを検出する方法は、handlerSearch(...)呼出しから戻る方法のみです。

例3-12 handlerSearch(...)の戻りによるリクエスト処理完了の検出

@Override
public void handleSearch(final RequestContext requestContext,
final SearchRequest request,
final SearchResultHandler resultHandler)
throws UnsupportedOperationException
{
// Pass the resultHandler reference received from the previous plug-in to
// the next plug-in. This implies that the next plug-in will post the
// result of the search request directly to the previous plug-in.
this.getConfiguration()
.getFirstNextPlugin()
.handleSearch(requestContext,
request,
resultHandler);

// The search request was processed by next plug-in.
}

3.4.2 検索エラーのインターセプト

後続のプラグインにより返される結果をインターセプトするには、プラグインが独自の結果ハンドラを提供する必要があります。

結果ハンドラでは2つのメソッドを定義します。

- リクエストが成功したときに次のプラグインにより呼び出されるhandleResult(Result)

- リクエストが成功したときに次のプラグインにより呼び出されるhandleErrorResult(Result)

検索結果ハンドラでは2つの追加メソッドを定義します。これらのメソッドは、次のプラグインがまだその他のエントリや参照を返せることを指定するTrue、または予想されるエントリや参照がもうないことを次のプラグインに示すFalseを返す必要があります。たとえば、サイズの限度に達した場合は予想されるエントリや参照はもうありません。

- エントリが返されたときに次のプラグインにより返されるhandleEntry(SearchResultEntry)

- 参照が返されたときに次のプラグインにより返されるhandleReference(DN, SearchResultReference)

OUDプラグインAPIには、oracle.oud.plugin.DefaultResultHandlerという名前のデフォルトの実装が結果ハンドラの実装のために提供されています。このJavaクラスが結果ハンドラ(ほとんどの場合、前のプラグインにより提供された結果ハンドラ)をラッピングし、受け取った結果をラッピングされた結果ハンドラにデフォルトで転送します。結果をキャプチャするために、プラグインが対象となる種類の結果をオーバーライドする必要があります。同様のデフォルト実装が検索結果ハンドラに存在します: oracle.oud.plugin.DefaultSearchResultHandler。

例3-13に、リクエストが不成功の場合に結果のログを記録する方法を示します。

例3-13 リクエストが不成功の場合の結果のロギング

public class EchoErrorResultHandler
extends DefaultResultHandler
{
public EchoErrorResultHandler(ResultHandler resultHandler)
{
super(resultHandler);
}

@Override
public void handleErrorResult(Result error)
{
// Echo the result of the request.
System.out.println("plug-in: error result " + error);

// Let the default behavior forward the result to the wrapped result
// handler
super.handleErrorResult(error);
}
}

例3-14に、リクエストが不成功の場合に検索操作で結果を印刷する方法を示します。

例3-14 検索操作での結果の印刷

@Override
public void handleSearch(final RequestContext requestContext,
final SearchRequest request,
final SearchResultHandler resultHandler)
throws UnsupportedOperationException
{
// The result handler passed to the next plug-in will echo the result in
// case the request was not successful.
this.getConfiguration()
.getFirstNextPlugin()
.handleSearch(requestContext,
request,
new EchoErrorResultHandler(resultHandler));

// The search request was processed by next plug-in.
}

次のことに注意してください。

- 結果ハンドラはリクエストに関連付けられていません。リクエストに対する参照を結果ハンドラ内に保持することで関連付けを維持するのは開発者の判断によります。

- 受け取ったリクエストの各インスタンスごとに、カスタムの結果ハンドラの新しいインスタンスが必要です。

1. 検索リクエストのエラーのログを記録するために、上に示したようにサンプル・プラグインを変更します。

2. Oracle Unified Directoryインスタンスを再起動してJARファイルの変更を有効にします。

1. OUDインスタンスを停止します。

UNIX、Linux

$ cd instance-directory/OUD/bin
$ stop-ds

Windows

C:\> cd instance-directory\OUD\bat
C:\> stop-ds

2. プラグインJARファイルをlibディレクトリにコピーします。

UNIX、Linux

# cp plugin.jar lib

Windows

C:\> copy plugin.jar lib

3. OUDインスタンスを再起動します。

UNIX、Linux

# start-ds

Windows

C:\> start-ds

3. 次のコマンドを実行して、存在しないユーザーを検索します。

UNIX、Linux

ldapsearch --hostname localhost --port 1389 --bindDN "cn=directory manager" --bindPasswordFile /tmp/password --searchScope sub --baseDN "uid=user.unknown,ou=people,dc=example,dc=com" "(objectclass=*)"
the command displays
SEARCH operation failed
Result Code:  32 (No Such Entry)
Additional Information:  The search base entry 'uid=user.unknown,ou=people,dc=example,dc=com' does not exist
Matched DN:  ou=people,dc=example,dc=com

Windows

ldapsearch --hostname localhost --port 1389 --bindDN "cn=directory manager" --bindPasswordFile C:\tmp\password  --searchScope sub --baseDN "uid=user.unknown,ou=people,dc=example,dc=com" "(objectclass=*)"
the command displays
SEARCH operation failed
Result Code:  32 (No Such Entry)
Additional Information:  The search base entry 'uid=user.unknown,ou=people,dc=example,dc=com' does not exist
Matched DN:  ou=people,dc=example,dc=com

各コマンドごとに、ログ・ファイル
(UNIX、Linuxではinstance-dir/OUD/logs/server.out、またはWindowsではinstance-dir\OUD\logs\server.out)
に次のような情報を含む必要があります。

plug-in: error result Result(resultCode="No Such Entry", matchedDN="ou=people,dc=example,dc=com", diagnosticMessage="The search base entry 'uid=user.unknown,ou=people,dc=example,dc=com' does not exist", referrals=null, controls=[])

3.4.3 返されたエントリのカウント

例3-15では、検索リクエストにより返されたエントリをカウントしてそのログを記録します。EntryCounterResultHandlerは、handleEntry(...)メソッドが呼び出されるたびにカウンタの値を増やします。

例3-15 検索リクエストにより返されたエントリのカウント

public class EntryCounterResultHandler
extends DefaultSearchResultHandler
{
// The number of search result entries returned by this search result
// handler.
private int entriesCount;

public EntryCounterResultHandler(SearchResultHandler resultHandler)
{
super(resultHandler);
}

@Override
public boolean handleEntry(SearchResultEntry entry)
{
this.entriesCount++;

return super.handleEntry(entry);
}

public int getEntriesCount()
{
return this.entriesCount;
}
}

検索リクエスト・ハンドラは、処理された各検索リクエストごとに返されたエントリをカウントする結果ハンドラを渡すように変更されます。次のプラグインによりリクエストが処理された後、返されたエントリの数がログに記録されます。

例3-16 検索リクエスト・ハンドラの変更

@Override
public void handleSearch(final RequestContext requestContext,
final SearchRequest request,
final SearchResultHandler resultHandler)
throws UnsupportedOperationException
{
EntryCounterResultHandler counter =
new EntryCounterResultHandler(resultHandler);

// The result handler passed to the next plug-in will count the number of
// entries returned by the next plug-in.
this.getConfiguration()
.getFirstNextPlugin()
.handleSearch(requestContext,
request,
counter);

// The search request was processed by next plug-in.
System.out.println(String.format("plug-in: request %s returned %d entries",
request,
counter.getEntriesCount()));

}

検索リクエストで返されたエントリの個数をログに記録する手順は次のとおりです。

1. サンプル・プラグインを上の例3-16に示されているように変更します。

2. Oracle Unified Directoryインスタンスを再起動してJARファイルの変更を有効にします。

1. OUDインスタンスを停止します。

UNIX、Linux

$ cd instance-directory/OUD/bin
$ stop-ds

Windows

C:\> cd instance-directory\OUD\bat
C:\> stop-ds

2. プラグインJARファイルをlibディレクトリにコピーします。

UNIX、Linux

# cp plugin.jar lib

Windows

C:\> copy plugin.jar lib

3. OUDインスタンスを再起動します。

UNIX、Linux

# start-ds

Windows

C:\> start-ds

3. 次のコマンドを実行して、登録されたすべてのユーザーを表示します。

UNIX、Linux

ldapsearch --hostname localhost --port 1389 --bindDN "cn=directory manager" --bindPasswordFile /tmp/password --searchScope sub --baseDN "ou=people,dc=example,dc=com" "(objectclass=*)"

Windows

ldapsearch --hostname localhost --port 1389 --bindDN "cn=directory manager" --bindPasswordFile C:\tmp\password --searchScope sub --baseDN "ou=people,dc=example,dc=com" "(objectclass=*)"

各コマンドごとに、ログ・ファイル
(UNIXまたはLinuxではinstance-dir/OUD/logs/server.out、Windowsではinstance-dir\OUD\logs\server.out)
に次のような情報を含む必要があります。

plug-in: request SearchRequest(name=ou=people,dc=example,dc=com, scope=sub, dereferenceAliasesPolicy=never, sizeLimit=0, timeLimit=0, typesOnly=false, filter=(objectClass=*), attributes=[], controls=[]) returned 51 entries
the number of returned entries corresponds to the 50 users plus the entry ou=people,dc=example,dc=com

3.5 フィルタ処理

場合によって、アプリケーションで検索リクエストに含まれたフィルタとの相互作用が必要なことがあります。この相互作用はビジター・デザイン・パターンに基づいたメカニズムにより指定され、Javaインタフェースoracle.oud.types.FilterVisitor<R,P>により定義されています。

LDAPプロトコルではフィルタのタイプが10個指定されています: and、or、not、equalityMatch、substrings、greaterOrEqual、lessOrEqual、present、approxMatchおよびextensibleMatch。

ビジター・フィルタでは、フィルタの各タイプごとにvisitAndFilter(...)、visitOrFilter(...)などのハンドラを定義します。

フィルタが解析される際、解析対象のフィルタを構成するフィルタのタイプが識別されます。識別したタイプに関連付けられたビジター・メソッドが順番に呼び出されます。

FilterVisitor<R,P>は2つのパラメータをとります:

- <R>は各ビジター・ハンドラで返されるタイプです。

- <P>は各ビジター・ハンドラに対して提供できるパラメータです。

例3-17では、解析対象のフィルタにおける属性の存在をチェックするFilterVisitorの実装が提供されます。objectclass=*のように属性が値*に関連付けられている場合、属性がフィルタに存在します。その場合、<R>が評価の結果に対応します。<R>は、属性が解析対象のフィルタに存在する場合はTRUE、属性がない場合はFALSEの値を持つブール値として定義されています。<P>はパラメータで、どの属性をチェックする必要があるかを定義する文字列に対応します。解析対象のフィルタがobjectclass=*の場合、パラメータobjectclassを使用してビジターを呼び出すとTRUEが返されます。他の値はFALSEを返します。

サブフィルタ(and、orおよびnot)で構成されたビジターは、それを構成しているすべてのサブフィルタにアクセスしてチェックを転送します。

例3-17では、説明のために、関連するビジターも情報を記録しています。

例3-17 解析対象のフィルタにおける属性の存在チェック

private class PresenceOfFilterVisitor
implements FilterVisitor<Boolean,
String>
{
@Override
public Boolean visitAndFilter(final String presenceName,
final List<Filter> subFilters)
{
System.out.println("plug-in: visit AND with " + subFilters);

boolean result = false;

// Iterate through all sub filters with this filter visitor.
for(Filter subFilter: subFilters)
{
result = subFilter.accept(this, presenceName);

if ( result )
{
break;
}
}

return result ? Boolean.TRUE : Boolean.FALSE;
}

@Override
public Boolean visitApproxMatchFilter(final String presenceName,
final String attributeDescription,
final ByteString assertionValue)
{
return Boolean.FALSE;
}

@Override
public Boolean visitEqualityMatchFilter(final String presenceName,
final String attributeDescription,
final ByteString assertionValue)
{
System.out.println("plug-in: visit EQUAL with " + attributeDescription + "=" + assertionValue);

return Boolean.FALSE;
}

@Override
public Boolean visitExtensibleMatchFilter(final String presenceName,
final String matchingRule,
final String attributeDescription,
final ByteString assertionValue,
final boolean dnAttributes)
{
return Boolean.FALSE;
}

@Override
public Boolean visitGreaterOrEqualFilter(final String presenceName,
final String attributeDescription,
final ByteString assertionValue)
{
return Boolean.FALSE;
}

@Override
public Boolean visitLessOrEqualFilter(final String presenceName,
final String attributeDescription,
final ByteString assertionValue)
{
return Boolean.FALSE;
}

@Override
public Boolean visitNotFilter(final String presenceName,
final Filter subFilter)
{
System.out.println("plug-in: visit NOT with " + subFilter);

// Visit the associated filter with this filter visitor.
return subFilter.accept(this, presenceName);
}

@Override
public Boolean visitOrFilter(final String presenceName,
final List<Filter> subFilters)
{
System.out.println("plug-in: visit OR with " + subFilters);

boolean result = false;

// Iterate through all sub filters with this filter visitor.
for(Filter subFilter: subFilters)
{
result = subFilter.accept(this, presenceName);

if ( result )
{
break;
}
}

return result ? Boolean.TRUE : Boolean.FALSE;
}

@Override
public Boolean visitPresentFilter(final String presenceName,
final String attributeDescription)
{
System.out.println("plug-in: visit Presence with '" + attributeDescription + "'");

return presenceName.equalsIgnoreCase(attributeDescription) ? Boolean.TRUE
: Boolean.FALSE;
}

@Override
public Boolean visitSubstringsFilter(final String presenceName,
final String attributeDescription,
final ByteString initialSubstring,
final List<ByteString> anySubstrings,
final ByteString finalSubstring)
{
return Boolean.FALSE;
}

@Override
public Boolean visitUnrecognizedFilter(final String presenceName,
final byte filterTag,
final ByteString filterBytes)
{
return Boolean.FALSE;
}
}

例3-18は、プラグインにより処理される検索リクエスト・フィルタにおけるobjectclass=*の存在を検証してログを記録します。

例3-18 objectclass=*の存在の検証およびロギング

@Override
public void handleSearch(final RequestContext requestContext,
final SearchRequest request,
final SearchResultHandler resultHandler)
throws UnsupportedOperationException
{
Filter filter = request.getFilter();

System.out.println("plug-in: visitor returned "
+ filter.accept(new PresenceOfFilterVisitor(),
"objectclass"));

// Pass the resultHandler reference received from the previous plug-in to
// the next plug-in. This implies that the next plug-in will post the
// result of the search request directly to the previous plug-in.
super.handleSearch(requestContext,
request,
resultHandler);

// The search request was processed by next plug-in.
}

プラグインにより処理される検索リクエスト・フィルタにおけるobjectclass=*の存在を検証してログを記録する手順は次のとおりです。

1. サンプル・プラグインを上の例3-18に示されているように変更します。

2. Oracle Unified Directoryインスタンスを再起動してJARファイルの変更を有効にします。

1. OUDインスタンスを停止します。

UNIX、Linux

$ cd instance-directory/OUD/bin
$ stop-ds

Windows

C:\> cd instance-directory\OUD\bat
C:\> stop-ds

2. プラグインJARファイルをlibディレクトリにコピーします。

UNIX、Linux

# cp plugin.jar lib

Windows

C:\> copy plugin.jar lib

3. OUDインスタンスを再起動します。

UNIX、Linux

# start-ds

Windows

C:\> start-ds

3. 次のコマンドを実行して、登録されたすべてのユーザーを表示します。

UNIX、Linux

ldapsearch --hostname localhost --port 1389 --bindDN "cn=directory manager" --bindPasswordFile /tmp/password --searchScope sub --baseDN "ou=people,dc=example,dc=com" "(objectclass=*)"

Windows

ldapsearch --hostname localhost --port 1389 --bindDN "cn=directory manager" --bindPasswordFile C:\tmp\password --searchScope sub --baseDN "ou=people,dc=example,dc=com" "(objectclass=*)"

各コマンドごとに、ログ・ファイル
(UNIXまたはLinuxではinstance-dir/OUD/logs/server.out、またはWindowsではinstance-dir\OUD\logs\server.out)
に次のような情報を含む必要があります。

plug-in: visit Presence with 'objectClass' plug-in: visitor returned true

異なるフィルタでコマンドを実行すると、ビジター・メカニズムがどのように機能するかが示されます。フィルタ&(|(!(uid=user.1)))で検索すると次のログが記録されます。

plugin: visit AND with [(|(!(uid=user.1)))]
plugin: visit OR with [(!(uid=user.1))]
plugin: visit NOT with (uid=user.1)
plugin: visit EQUAL with uid=user.1
plugin: visitor returned false

3.6 内部操作

APIはLDAPに似た呼出しをOUD内に作成するメソッドを提供します。

内部LDAPリクエストは、クライアントからの外部リクエストによって直接開始されるのではなく、プラグインによって内部的に開始されるという意味で内部的です。内部リクエスト・コールは、プラグインで、クライアント・リクエストが存在しない操作をOUDで実行する必要がある場合に使用します。たとえば、プラグインでユーザー・エントリに対する検索リクエストを実行し、クライアントからバインド・リクエストを受け取ったときに追加の資格証明を取得できます。

oracle.oud.plugin.RequestManagerコールバックは、内部操作を含め、OUDにより処理されたすべての操作に対して起動されます。多くの場合、プラグインはクライアント・アプリケーションによって直接開始された操作に対してのみ適用されます。内部操作と通常の操作は、リクエスト・オブジェクトでisInternal()メソッドを呼び出すことで区別できます。

3.6.1 内部リクエストの作成

内部LDAPリクエストは、oracle.oud.plugin RequestBuilderオブジェクト・クラスを介して作成されます。requestBuilderに対する参照は、クライアント・アプリケーションから受け取ったリクエストと関連付けられたRequestContextからgetRequestBuilder()を介して取得できます。

内部操作を実行するために使用されるユーザー資格証明は、作成時に指定されています。一般に、内部操作は現在のセキュリティ・コンテキスト内で、プラグインをトリガーしたユーザーの資格証明を使用して実行されます。場合によっては、内部操作に特権アクセスが必要なことがあります。たとえば、バインド・リクエストを処理する前に実行される内部検索は、その時点で現在のユーザーがまだ認証されていないためanonymousとして実行されます。

特権リクエストを作成するには、呼出しrequestContext.getRequestBuilder(true)とともに特権RequestBuilderを使用します。このビルダーから作成したリクエストのみがroot.otherwiseの特権で実行し、デフォルトのrequestBuilderをrequestContext.getRequestBuilder(false)を介して取得できます。

3.6.2 内部リクエストの起動

OUDプラグインAPIには、内部リクエストを起動するための2つの方法が提供されています。最初のモードでは、プラグインは該当する後続ワークフロー要素がチェーン内に構成されていれば、それを起動することで現在のプラグイン・ワークフロー内で呼出しを実行します。2つ目のモードでは、プラグインはLDAPに似た呼出しをエンド・クライアントからのものと同様にOUD内に作成します。各呼出しには、ルーターが操作に適したワークフローを選択できるようにする機能が提供されます。

内部リクエストからの結果は、結果ハンドラを使用して、第3.4項「結果の処理」に説明されているようにして取得できます。

3.6.2.1 モード1

プラグインの次のワークフロー要素は、プラグイン構成から呼出しconfiguration.getNextPlugins()を介して取得できます。これらのプラグインの名前は、getName()メソッドを使用して取得できます。名前を取得した後、次のワークフロー要素が複数構成されている場合にはどのワークフロー要素にリクエストを送る必要があるかを選択できます。たとえば、ロード・バランシング・サービスを提供しているプラグインには複数の後続ワークフロー要素が構成されている可能性があります。内部リクエストを開始した後、ターゲット・ワークフローの場所が決まれば、適切なハンドラ・メソッドを介してリクエストを発行できます。

例3-19「プラグインの後続ワークフロー要素の起動」では、属性customTimeStampを受け入れるようにサーバー・スキーマを変更する必要があります。このプラグインは、内部のmodify操作を使用してログイン時刻をユーザー・エントリ属性customTimeStampに格納します。

処理の時点でバインドはまだ完了していないため、特権リクエスト・ビルダーgetRequestBuilder(true)を使用する必要があることに注意してください。したがって、ユーザーは匿名とみなされます。

例3-19 プラグインの後続ワークフロー要素の起動

@Override
public void handleBind(final RequestContext requestContext,
final int version,
final BindRequest request,
ResultHandler resultHandler)
throws UnsupportedOperationException
{

...

// Get a privileged request builder
RequestBuilder myRequestBuilder = requestContext.getRequestBuilder(true);

// Create a new modify request using that builder
// Target LDAP entry is the user about to be authenticated
ModifyRequest addTimestampModifyRequest = myRequestBuilder.newModifyRequest(request.getName());

// Populate the modification object
addTimestampModifyRequest.addModification(ModificationType.REPLACE,
"customTimeStamp", System.currentTimeMillis()) ;

// Create a ResultHandler to catch the result of the modify operation
ResultHandler modifyResultHandler = new CustomModifyResultHandler(resultHandler);

// submit the request to the next workflow element
getConfiguration().getFirstNextPlugins().handleModify(requestContext,
addTimestampModifyRequest, modifyResultHandler);

...

}

3.6.2.2 モード2

このモードでは、リクエストは内部リクエスト・マネージャ・オブジェクトを介して実行されます。このオブジェクトはRequestContextからメソッドgetInternalRequestManager()を介して取得できます。その後、リクエストを適切なハンドラ・メソッドを介して発行できます。

各リクエストは適切なワークフローにルーティングされるため、所定のワークフロー内のプラグインにより開始された内部リクエストが同じワークフローにルーティングされる可能性があります。プラグインが自分自身で生成したリクエストをインターセプトする場合があります。内部操作の処理で予期しない再帰的ループを防ぐために、内部操作が発行されたときに追加の添付(コンテキスト情報)を内部操作に添付できます。この添付は、新しいリクエストを受け取ったときにプロキシにより取得およびチェックしてループを検出し適切なアクションをとることができます。添付は、リクエスト・オブジェクトにより実装されたAttachmentHolderインタフェースにより管理できます。

例3-20では、変更の前にユーザーのエントリ内でcustomTimeStamp属性を検索しています。変更リクエストが現在のユーザー資格証明付きで作成され、内部リクエスト・マネージャを介してエンド・クライアントからのものと同様に発行されます。分かりやすくするために例外処理をコード例から削除しました。

例3-20 内部リクエスト・マネージャを使用した内部操作の実行

public void handleModify(final RequestContext requestContext,
final ModifyRequest request,
ResultHandler resultHandler)
throws UnsupportedOperationException
{
...

// Get a standard request builder
RequestBuilder myRequestBuilder = requestContext.getRequestBuilder(false);

// Create a new search request using that builder
// Target LDAP entry is the user about to be modified
SearchRequest getLastTimestampRequest = myRequestBuilder.newSearchRequest(
request.getName(), SearchScope.BASE_OBJECT,
getPluginContext().getTypeBuilder().newFilter("(objectclass=*)"),
"currentTimeStamp");

// Create a ResultHandler to catch the result of the search operation
SearchResultHandler searchResultHandler = new CustomSearchResultHandler(resultHandler);

// submit the request via the internal request manager
requestContext.getInternalRequestManager().handleSearch(requestContext,
getLastTimestampRequest, searchResultHandler);

...
}

例3-21に、ループを処理する方法を示します。検索リクエストが初めてプラグインにより受け取られたときは、名前がnbLoopsの添付はありません。プラグインは添付(name=nbLoops, value=1)を含むリクエストにフラグを設定し、その後そのリクエストを内部リクエスト・マネージャに対してリバランスします。検索リクエストは最終的にプラグインに戻ります。プラグインが2度目に添付を取得したとき、値を2に増やし、リクエストに取得したものを設定します。その後、内部リクエスト・マネージャに対してリバランスします。3度目、値(2)はMAX_LOOPSより大きいか等しいため、プラグインはリクエストを次のワークフロー要素に送ります(method super.handleSearch(...)を使用

例3-21 添付処理: ループ処理

// Let search requests loop 2 times within the internal request manager,
// before sending them to next WorkflowElement
public static final int MAX_LOOPS = 2;

@Override
public void handleSearch(RequestContext requestContext,
SearchRequest request,
SearchResultHandler resultHandler)
throws UnsupportedOperationException
{
String name = "nbLoops";
Integer nbLoops = 0;
Set<String> attachmentNames = request.getAttachmentNames();

// Get "nbLoops" attachment value, if ound in the request
if (attachmentNames.contains(name))
{
nbLoops = (Integer) request.getAttachment(name);
}

// if we reach max number of loops...
if (nbLoops >= MAX_LOOPS)
{
// ...remove attachment
request.removeAttachment(name);

// forward request to next WorkflowElement
super.handleSearch(requestContext,
request,
resultHandler);
} else
{
// increment nbLoops value
nbLoops++;

// set attachment nbLoops new value
request.setAttachment(name, nbLoops);

// log request (as internal op) + attachment value
Logger logger = requestContext.getLogger();
HashMap<String, String> map = new HashMap<String, String>();
map.put("nbLoops", Integer.toString(nbLoops));
logger.logSearchRequestIntermediateMessage(request, map);

// re-balance tge search request via the internal request manager
requestContext.getInternalRequestManager().handleSearch(requestContext,
request,
resultHandler);
}

3.7 エラー処理

プラグイン実装は、予期しないエラー状態が発生したときにPluginExceptionのサブクラスを発生させることができます。サーバーの動作は例外がいつ発生したかによります。LDAP操作の処理中に発生した場合、クライアント・アプリケーションに対してLDAPエラー80「内部エラー」が返されます。プラグインの初期化中に発生した場合、プラグインは無効になります。

3.8 ロギングとデバッグ

プラグインAPI内で生成されたキャッチされない例外は、OUDデバッグ・ログにWarningレベルで記録されます。

プラグインの標準出力は、そのプラグインをホストしているOUDディレクトリ・サーバー・インスタンスにあるログ・ファイル(UNIXまたはLinuxではinstance-dir/OUD/logs/debug、Windowsではinstance-dir\OUD\logs\debug)にリダイレクトされます。

プラグインの開発中に、次のdsconfigコマンドを使用してデバッグ・ログを有効にできます。

dsconfig set-log-publisher-prop \ --publisher-name "File-Based Debug Logger" \ --set default-debug-level:warning \ --set enabled:true

プラグイン実装は、OUD access、errorまたはdebugログにoracle.oud.plugin.RequestContext.Loggerインタフェースを使用してメッセージを記録できます。

3.8.1 クライアント・リクエストのサービス中にプラグインをデバッグする手順

1. instance-directory/config/java.propertiesから取得したstart-ds.java-argsの値プラス-Xdebug -Xrunjdwp:transport=dt_socket,address=127.0.0.1:8888,server=y,suspend=nを使用してOPENDS_JAVA_ARGSをエクスポートします

2. OUDインスタンスを再起動します。
これでデバッグ・ポート8888が開きます。

3. ポート8888上のOUDプロセスにアタッチし、IDEを介してプラグインをデバッグします。

3.8.2 プラグイン初期化のデバッグの手順

1. instance-directory/config/java.propertiesから取得したstart-ds.java-argsの値プラス-Xdebug -Xrunjdwp:transport=dt_socket,address=127.0.0.1:8888,server=y,suspend=yを使用してOPENDS_JAVA_ARGSをエクスポートします

2. OUDインスタンスを再起動します。
これでデバッグ・ポート8888が開きます。

3. この時点で、(pluginInitialization()メソッドを使用して)プラグイン初期化コードをデバッグする前にポート8888上のOUDプロセスに3回アタッチする必要があります。

java.propertiesファイルを変更するよりもOPENDS_JAVA_ARGSをエクスポートしてください。OPENDS_JAVA_ARGSのエクスポートにOUDインスタンス構成ファイルの変更は不要で、本番でデバッグJVM argsがエクスポートされる危険はありません。

オラクル社の法律上の注意点について

コピーライトについて

Copyright © 1994-2014, Oracle and/or its affiliates.All rights reserved.

商標と登録商標について

OracleおよびJavaはOracle Corporationおよびその関連企業の登録商標です。その他の名称は、それぞれの所有者の商標または登録商標です。

Intel、Intel Xeonは、Intel Corporationの商標または登録商標です。すべてのSPARCの商標はライセンスをもとに使用し、SPARC International, Inc.の商標または登録商標です。AMD、Opteron、AMDロゴ、AMD Opteronロゴは、Advanced Micro Devices, Inc.の商標または登録商標です。UNIXは、The Open Groupの登録商標です。

ライセンス制約の保証と結果的に生じる損害の免責

このソフトウェアおよび関連ドキュメントの使用と開示は、ライセンス契約の制約条件に従うものとし、知的財産に関する法律により保護されています。ライセンス契約で明示的に許諾されている場合もしくは法律によって認められている場合を除き、形式、手段に関係なく、いかなる部分も使用、複写、複製、翻訳、放送、修正、ライセンス供与、送信、配布、発表、実行、公開または表示することはできません。このソフトウェアのリバース・エンジニアリング、逆アセンブル、逆コンパイルは互換性のために法律によって規定されている場合を除き、禁止されています。

保証免責

ここに記載された情報は予告なしに変更される場合があります。また、誤りが無いことの保証はいたしかねます。誤りを見つけた場合は、オラクル社までご連絡ください。

制限付権利

このソフトウェアまたは関連ドキュメントを、米国政府機関もしくは米国政府機関に代わってこのソフトウェアまたは関連ドキュメントをライセンスされた者に提供する場合は、次の通知が適用されます。

U.S. GOVERNMENT END USERS: Oracle programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, delivered to U.S. Government end users are "commercial computer software" pursuant to the applicable Federal Acquisition Regulation and agency-specific supplemental regulations.As such, use, duplication, disclosure, modification, and adaptation of the programs, including any operating system, integrated software, any programs installed on the hardware, and/or documentation, shall be subject to license terms and license restrictions applicable to the programs.No other rights are granted to the U.S. Government.

危険な用途への使用について

このソフトウェアもしくはハードウェアは様々な情報管理アプリケーションでの一般的な使用のために開発されたものです。このソフトウェアもしくはハードウェアは、危険が伴うアプリケーション（人的傷害を発生させる可能性があるアプリケーションを含む）への用途を目的として開発されていません。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用する際、安全に使用するために、適切な安全装置、バックアップ、冗長性（redundancy）、その他の対策を講じることは使用者の責任となります。このソフトウェアもしくはハードウェアを危険が伴うアプリケーションで使用したことに起因して損害が発生しても、オラクル社およびその関連会社は一切の責任を負いかねます。

第三者のコンテンツ、製品、サービスに対する免責事項

このソフトウェアまたはハードウェア、そしてドキュメントは、第三者のコンテンツ、製品、サービスへのアクセス、あるいはそれらに関する情報を提供することがあります。オラクル社およびその関連会社は、第三者のコンテンツ、製品、サービスに関して一切の責任を負わず、いかなる保証もいたしません。オラクル社およびその関連会社は、第三者のコンテンツ、製品、サービスへのアクセスまたは使用によって損失、費用、あるいは損害が発生しても一切の責任を負いかねます。

ドラフトのアルファ版およびベータ版ドキュメントについて

このドキュメントが試作版の場合:

このドキュメントは試作版であり、デモおよび暫定使用のみを目的としたものです。このソフトウェアを使用するハードウェアに限定するものではありません。オラクル社およびその関連会社は、このドキュメントに関して一切の責任を負わず、いかなる保証もいたしません。また、このドキュメントを使用したことによって損失、費用、あるいは損害が発生しても、一切の責任を負いかねます。