ヘッダーをスキップ
Oracle® Fusion Middleware Oracle Virtual Directory管理者ガイド
11gリリース1(11.1.1)
B55922-05
  目次へ
目次
索引へ移動
索引

前へ
前へ
 
次へ
次へ
 

18 Oracle Virtual Directoryのカスタマイズ

この章では、Oracle Virtual Directoryのカスタマイズ方法について説明します。この章の内容は次のとおりです。

18.1 Oracle Directory Services Managerへのローカライズされた言語の設定

Oracle Virtual Directoryには、次の言語で、Oracle Directory Services Managerインタフェースのローカライズされた翻訳が用意されています。

Webブラウザの言語設定を使用して、Oracle Directory Services Managerインタフェースに言語を設定できます。言語設定に関する固有の情報は、使用しているWebブラウザのドキュメントを参照してください。


注意:

Oracle Directory Services Managerの管理者アクセスを持つユーザー(通常はcn=orcladmin)のみがOracle Directory Services Managerにログインできます。

18.2 カスタム・アダプタの作成および構成

Oracle Virtual Directoryではカスタム・アダプタの作成機能もサポートされています。これには、定義済のAPIによってほとんどすべてのデータ・ソースに接続できるプラグインを使用します。たとえば、カスタム・アダプタを使用して、Webサービスで入手できる情報を抽出できます。カスタム・アダプタは、それ自体には機能がないアダプタです。かわりに、アダプタ・レベルのプラグインを構成してその機能を実装できるプレースホルダです。デフォルトでは、カスタム・アダプタはどのデータ・ソースにもマップされていません。Oracle Directory Services Managerの「プラグイン」タブでカスタム・アダプタに追加されるDiameterプラグインなどのプラグインは、カスタム・アダプタにデータを提供します。通常、カスタム・アダプタは、Oracle Virtual Directoryを、Webサービスなど非LDAPサービスまたは非データベース・サービスに接続する必要がある顧客によって作成されます。

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

18.2.1 カスタム・アダプタの作成

Oracle Directory Services Managerを使用してカスタム・アダプタを作成するには、次の手順を実行します。

  1. Oracle Directory Services Managerにログインします。

  2. タスク選択バーから「アダプタ」を選択します。「アダプタ」ナビゲーション・ツリーが表示されます。

  3. 「アダプタの作成」ボタンをクリックします。新規アダプタ・ウィザードが表示されます。

  4. アダプタのタイプを定義するには、次の手順を実行します。

    1. 「アダプタ・タイプ」リストから「カスタム」を選択します。

    2. 「アダプタ名」フィールドにカスタム・アダプタの一意の名前を入力します。アダプタ名の値は、そのアダプタを参照する必要のある他の構成フィールドで使用されます。

    3. 「アダプタ・テンプレート」リストから「デフォルト」テンプレートを選択します。

    4. 「次へ」をクリックします。「設定」画面が表示されます。

  5. 「アダプタ接尾辞/ネームスペース」フィールドに有効なベースDNを(DN形式で)入力します。このフィールドには、アダプタが情報を提供するルートDNを定義します。定義されているDNとその下の子エントリには、アダプタのネームスペースが含まれます。アダプタ接尾辞フィールドに、戻されるエントリのベースDN値を入力します。たとえば、「アダプタ接尾辞/ネームスペース」フィールドにdc=mydomain,dc=comと入力すると、すべてのエントリはdc=mydomain,dc=comで終わります。

  6. 「次へ」をクリックします。カスタム・アダプタの設定の概要が表示されます。設定を確認し、「終了」をクリックしてカスタム・アダプタを作成します。「アダプタ」ツリーに、カスタム・アダプタが表示されます。

カスタム・アダプタを作成したら、「カスタム・アダプタの構成」の手順に従って構成できます。

18.2.2 カスタム・アダプタの構成

この項では、カスタム・アダプタ設定の構成方法を説明します。この項の内容は次のとおりです。

18.2.2.1 カスタム・アダプタの一般設定の構成

カスタム・アダプタを作成したら、「アダプタ」ツリーでアダプタ名をクリックし、「一般」タブをクリックして次に示すフィールドに値を設定し、「適用」をクリックしてアダプタの一般設定を構成できます。

ルート

このフィールドには、アダプタが情報を提供するルートDNを定義します。定義されているDNとその下の子エントリには、アダプタのネームスペースが含まれます。このフィールドに入力する値は、戻されるエントリのベースDN値です。たとえば、このフィールドにdc=mydomain,dc=comと入力すると、すべてのエントリはdc=mydomain,dc=comで終わります。

アクティブ

アダプタは、アクティブ(有効)または非アクティブ(無効)として構成できます。非アクティブに構成されたアダプタは、サーバーの再起動時やアダプタの起動の試行時には起動しません。非アクティブの設定は、古い構成を使用可能な状態にしておく場合や、構成から削除せずにスタンバイ状態にしておく場合に使用します。デフォルト設定はアクティブです。

18.2.2.2 アダプタのルーティングの構成

アダプタを作成したら、「アダプタ」ツリーでアダプタ名をクリックして「ルーティング」タブをクリックし、「ルーティング設定の概要」を参照することで、そのアダプタのルーティングを構成できます。


注意:

バインド操作をサポートするかどうかが不明なカスタム・アダプタを定義する際には、「バインド・サポート」ルーティング設定を有効化します。

18.2.2.3 アダプタ・プラグインおよびマッピングの構成

アダプタを作成したら、「アダプタ」ツリーでアダプタ名をクリックして「プラグイン」タブをクリックし、「アダプタ・プラグインの管理」および「アダプタへのマッピングの適用」を参照することで、そのアダプタにプラグインおよびマッピングを適用できます。

18.3 カスタムJavaプラグインの開発

この項では、Oracle Virtual DirectoryのカスタムJavaプラグインの開発方法について説明します。この項の内容は次のとおりです。

18.3.1 概要

Oracle Virtual Directoryでは、Oracle Virtual Directoryのパススルー時にLDAP操作を処理および操作できるカスタムJavaプラグインを作成してデプロイできます。プラグインは、すべてのリクエストを把握し処理するグローバル・レベル、または特定のアダプタに対するリクエストのみを把握し処理するアダプタ・レベルに配置できます。また、特定の操作やネームスペースに対して実行されるようにプラグインを作成およびデプロイすることもできます。


注意:

カスタムJavaプラグインを使用して属性名を変更する場合、DB_Groupsマッピングで行われるように、カスタム・コードが受信フィルタ・オブジェクトを上書きする場合にのみ、Oracle Virtual Directoryで、名前の変更された属性/値の検索がサポートされます。

Oracle Virtual Directoryの各プラグインには、表18-1にリストされているように、特定の実装ポイントがあります。

表18-1 プラグインの実装ポイント

実装ポイント 説明

構成

プラグインの構成データ。構成のカスタム部分は、初期化パラメータの名前と値のペアで構成されています。

起動/停止

init(PluginInit initParams, String name)およびdestroy()メソッドは、プラグインの初期化および初期化解除時に呼び出されます。

可用性

available(Chain chain, DirectoryString base)メソッドは、プラグインを実行するかどうかを決定するために、プラグインの実行前に呼び出されます。

操作

呼び出される様々な操作メソッド。


この章では、表18-1にリストされている実装ポイントを説明して、カスタム・プラグインの作成方法を示します。この章では、バインド操作が失敗したか成功したかを検出するBad Password Countプラグインという仮想の例のプラグインについて説明します。操作が成功した場合は件数が消去され、バインドが失敗した場合は件数が増加します。仮想のBad Password Countプラグインを使用すると、不正なパスワード件数をディレクトリの外から変更できなくなります。


注意:

この章で説明するBad Password Countプラグインは仮想の例で、Oracle Virtual Directoryプラグインおよびそのチェーン・システムがどのように機能するかを示すために使用されます。作成すればサポートされますが、Oracle Virtual DirectoryにはBad Password Countプラグインは用意されていません。

18.3.2 チェーン・システムの概要

Oracle Virtual Directoryプラグインは、Java Servlet 2.3フィルタ・モデルに基づく実装に準拠しています。このモデルでは、前操作および後操作の処理、および操作を続行するかどうかの判断に 1 つのメソッドが使用されます。複数のプラグインが結合されて、プラグインのチェーンが形成されます。このチェーンの実装を例示するために、仮想の例であるBad Password Countプラグインが、ディレクトリに追加されるエントリに不正なパスワード件数属性を追加するかどうかを決定する次のような状況を考えてみます。

addメソッドが呼び出されたときにリクエストを操作でき、それにより、渡される属性とそれらの値を操作(たとえば、ActiveDirectoryを汎用LDAPディレクトリとしてマスキングしている場合にオブジェクト・クラス値inetOrgPersonuserに変更)したり、カスタム・アダプタなどでデータの記憶域を非ディレクトリ・システムまたはデータベース・システムにすることができます。仮想ディレクトリで、他のプラグインを使用してそのリクエストをさらに処理できるようにするには、chain.nextAddメソッドを呼び出します。ほとんどのプラグイン・メソッドには、対応するchain.next<XXX>メソッドがあります。プラグインによってリクエストをさらに処理することを許可しない場合は、chain.next<XXX>コールを省略できます。


注意:

アダプタ・タイプはプラグインとは無関係です。プラグインは、どのようなタイプのアダプタにも追加できます。

18.3.3 プラグインの実装ポイント

カスタム・プラグインを作成する前に、com.octetstring.vde.chain.Pluginインタフェースを実装するか、com.octetstring.vde.chain.BasePluginクラスを拡張するかを決定する必要があります。BasePluginクラスを使用すると、プラグイン開発者は、プラグインによって処理される操作用のメソッドのみを実装できます。この章で示す例のプラグインでは、BasePluginクラスを拡張して実装を簡略化しています。

この項の次に示す項では、Oracle Virtual Directoryのプラグインの実装ポイントについて説明します。

18.3.3.1 構成、開始および停止のプラグインの実装ポイント

プラグインの1番目の実装ポイントは構成です。プラグインは、Oracle Virtual Directory構成システムによって提供される、一連の単純な名前と値のペアを使用して構成されます。このペアは、プラグインのinitメソッドに対するparams引数を介してプラグイン開発者に提供されます。この章で示す例のプラグインには、次の構成オプションがあります。

  • countAttribute: 不正なパスワード件数を保存するすべてのユーザー・エントリに追加される属性。

  • addOnCreate: ユーザーの作成時にプラグインがこの属性を追加する場合にtrueに設定されるブール値。

  • objectClassForAdd: 属性が追加されるユーザーを表すオブジェクト・クラス。

  • ignoreOnModify: countAttributeの変更リクエストが無視される場合にtrueに設定されるブール値。

これらの構成オプションは、2番目の実装ポイントであるライフ・サイクル・メソッドで取得されます。initメソッドはサーバー起動時にプラグインを初期化する際に呼び出され、destroyメソッドはプラグインを停止する際に呼び出されます。例18-1に、サンプルのinitメソッドを示します。

例18-1 サンプルのinitメソッド

/**
 * Passes initialization information to the Plug-in
 * 
 * @param initParams
 *            Hashmap of key/value pairs specified in initial config
 * @param name
 *            The name specified in the config for this Plug-in
 */
public void init(PluginInit initParams, String name) throws ChainException {
       //the countAttribute parameter is required
       if (!initParams.containsKey(BadPasswordCount.CONFIG_COUNT_ATTRIBUTE)) {
            throw new ChainException(name + ": The "
               + BadPasswordCount.CONFIG_COUNT_ATTRIBUTE
               + " attribute is required");
       }
       this.countAttribute = new DirectoryString(initParams
                 .get(BadPasswordCount.CONFIG_COUNT_ATTRIBUTE));
       this.attribType = SchemaChecker.getInstance().getAttributeType(
            this.countAttribute);
       //determine if add on create
       this.addOnCreate = initParams
            .containsKey(BadPasswordCount.CONFIG_ADD_ON_CREATE)
            && initParams.get(BadPasswordCount.CONFIG_ADD_ON_CREATE)
            .equalsIgnoreCase("true");

       if (this.addOnCreate) {
             if (this.addOnCreate
                    && !initParams
                     .containsKey(BadPasswordCount.CONFIG_OBJECTCLASS_FOR_ADD)) {
             throw new ChainException(name
                   + ": When adding count attribute, the parameter "
                   + BadPasswordCount.CONFIG_OBJECTCLASS_FOR_ADD
                   + " is required");
             }

             String[] objectClasses = initParams
                    .getVals(BadPasswordCount.CONFIG_OBJECTCLASS_FOR_ADD);
             this.objectClasses = new HashSet();

             for (int i = 0, m = objectClasses.length; i < m; i++) {
                  this.objectClasses.add(new DirectoryString(objectClasses[i]));

             }
       } else {
               this.addOnCreate = false;
       }

       logger.info("Adding on create : " + this.addOnCreate);
       //determine if the modify operation should be ignored
       this.ignoreModify = initParams
            .containsKey(BadPasswordCount.CONFIG_IGNORE_MODIFY)
            && initParams.get(BadPasswordCount.CONFIG_IGNORE_MODIFY)
            .equalsIgnoreCase("true");

例18-1のメソッドでは、プラグインを設定するための初期化パラメータが確認されています。構成情報が不十分な場合は、プラグインにより例外がスローされ、サーバーによる操作目的での使用が可能になるようプラグインを構成できない原因になります。接続の解放またはサービスの停止が必要な場合以外は、destroyメソッドを実装する必要はありません。

18.3.3.2 可用性のプラグインの実装ポイント

使用可能な実装ポイントは、構成、開始および停止の実装ポイントに続きます。availableメソッドは、特定のLDAP操作に対する各プラグインの呼出しが可能になる前に呼び出されます。availableメソッドによりtrueが戻されると、プラグインが実行されます。例18-2では、availableメソッドによりRequestオブジェクトのignoreOnModifyオプションの有無が確認されています。それが定義されている場合、プラグインはスキップされます。同様に、addonCreateオプションがfalseに設定されている場合も、プラグインはスキップされます。

例18-2 ignoreOnModifyオプションの有無を確認するサンプルのメソッド

/**
 * Determines if a plugin is available for the current chain
 * 
 * @param chain
 * @param base
 * @return True or False if available for a particular chain & base
 */
public boolean available(Chain chain, DirectoryString base) {
 
       if (chain.getOperationType() == Chain.ADD_OP && !this.addOnCreate) {
             return false;
       } else if (chain.getOperationType() == Chain.MOD_OP
                  && this.ignoreOnModify) {
             return false;
       } else {
             return true;
       }
}

availableメソッドがtrueを戻すと、リクエストの操作部分が実行されます。

18.3.3.3 操作のプラグインの実装ポイント

最後の実装ポイントは、操作の実装です。例18-3に、次のバインド操作のコード実装を示します。

例18-3 バインド操作の実装の例

/**
 * Moves through the "bind" operation's chain
 * 
 * @param chain
 *            The current chain
 * @param dn
 *            The DN for the user
 * @param password
 *            The user's password
 * @param result
 *            The result of the bind
 */
public void bind(Chain chain, Credentials creds, DirectoryString dn,
            BinarySyntax password, Bool result) throws DirectoryException,
            ChainException {
 
       // Pre-event processing 
 
// calls the next plug-in in the chain (or comment out if a handler)
      try {
         chain.nextBind(creds, dn, password, result);
      } catch (DirectoryException e) {
            throw e;
      }
 
      // Post-event processing
      if (result.booleanValue()) {
            // success, reset count
            setPasswordCount(chain, creds, dn, 0);
      } else {
            Vector searchAttributes = new Vector();
            searchAttributes.add(this.countAttribute);
 
            ChainVector results = new ChainVector();
            try
            {
            chain.getVSI().get(chain.getRequest(), creds, dn,
                new Int8((byte) 0), ParseFilter.parse("(objectClass=*)"),
                new Bool(false), searchAttributes, results);
 
            if (results.size() > 0) {
                 EntrySet es = (EntrySet) results.get(0);
                 Entry entry = es.getNext();
                 Vector values = entry.get(this.countAttribute);
                 Syntax value = (Syntax) values.get(0);
                 IntegerSyntax is = new IntegerSyntax(value.getValue());
                 setPasswordCount(chain, creds, dn,
                               ((int) is.getLongValue()) + 1);
            } else 
            {
                  setPasswordCount(chain, creds, dn, 1);
            chain.getVSI().get(...);            
            }
            }
            catch (Exception ex)
            {
 
            }
            finally
            {
                for (EntrySet entrySet : results)
                    entrySet.cancelEntrySet();
            }

            }
      }
}
 
private void setPasswordCount(Chain chain, Credentials creds,
             DirectoryString dn, int count) throws DirectoryException,
             ChainException {
 
      Vector values = new Vector();
      values.add(new IntegerSyntax(count));
      EntryChange modify = new EntryChange(EntryChange.MOD_REPLACE,
                  this.countAttribute, values);
      Vector changes = new Vector();
      changes.add(modify);
      chain.getVSI().modify(chain.getRequest(), creds, dn, changes);
 
}

例18-3のメソッドでは、パスワード失敗件数がパスワード・ポリシーという形でディレクトリ内に維持されている例が示されています。メソッドでは、操作の前処理も実行されておらず、バインド操作の引継ぎも試行されていないことに注意してください。プラグインのbindメソッドがchain.nextBindメソッドをすぐに呼び出し、独自のロジックで続行する前にバインドが完了するまで待機します。コントロールがchain.nextBindから戻されてバインドが完了すると、プラグインによりバインドが成功したかどうかが確認されます。バインドが成功した場合には、プラグインにより失敗件数属性がゼロに設定されます。バインドが失敗した場合には、現行の失敗件数が取得され、増加した値が設定されます。

bindメソッドは、仮想サービス・インタフェース(VSI)を使用してバインディング・ユーザーのレコードを変更します。VSIインタフェースは、プラグインがグローバルにデプロイされているかアダプタのコンテキスト内にデプロイされているかにかかわらず、ディレクトリ情報への一貫したアクセス方法としてOracle Virtual Directory全体で使用できます。これはVSIが、現行のプラグインの後にチェーン内の次のプラグインを開始することにより、常にOracle Virtual Directoryをコールすることで実現されます。たとえば、プラグインの前にマッパーが存在し、プラグインの後にキャッシュが存在する場合、VSIへのコールはキャッシュのみを経由します。

このプラグインは、論理的にバインド失敗件数の保持を担うため、LDAPクライアントによる件数変更の試行を防止するために、プラグインのmodifyメソッドを実装する必要があります。例18-4のプラグインのmodifyメソッドは、count属性がmodify変更リストに含まれている場合に例外をスローするように実装されています。

例18-4 サンプルのmodifyメソッド

/**
 * Moves through the "modify" operation's chain
 * 
 * @param chain
 *            The current chain
 * @param creds
 *            The currnet user's credentials
 * @param name
 *            The name of the object being modified
 * @param changeEntries
 *            The group of EntryChange Objects
 */
public void modify(Chain chain, Credentials creds, DirectoryString name,
            Vector changeEntries) throws DirectoryException, ChainException {
 
       Iterator it = changeEntries.iterator();
       while (it.hasNext()) {
             EntryChange ec = (EntryChange) it.next();
             if (ec.getAttr().equals(this.countAttribute)) {
                throw new
                  DirectoryException(LDAPResult.CONSTRAINT_VIOLATION
                  .intValue(), "Can not modify password count attribute");
             }
       }

       chain.nextModify(creds, name, changeEntries);
 
 
}

ステータス・コードおよびメッセージとともにDirectoryExceptionがスローされています。この例外が別のプラグインによって捕捉されない場合、例外はメッセージとコードの両方でクライアントに戻されます。ignoreOnModifyが構成されているかどうかの判断はavailableメソッドに委任してあるため、この例では確認する必要はありません。設定されている場合、例18-4のプラグインのmodifyメソッドは呼び出されていません。

18.3.3.3.1 検索

検索は、他の操作とは異なり、1つではなく3つのメソッドを実装できます。第一のメソッドgetは他の操作メソッドと同様に機能し、プラグイン開発者は検索リクエストを前処理し、戻りを後処理できます。戻される各Entryを処理することもできますが、それを実行するとメモリー使用率の面で大変非効率的です。getメソッドの結果の処理では、クライアントに戻す前にすべての結果をメモリーに取得する必要があります。そのために、クライアントに戻すすべてのEntryに対して実行されるpostSearchEntryメソッドが用意されており、これによって属性を効率的な方法で変更または追加できます。また、検索操作が完了したマークを付けるpostSearchCompleteメソッドもあります。

postSearchEntry処理を効率的に使用するために、Oracle Virtual Directoryでは、EntrySetと呼ばれる特別なクラスを使用して結果セットの処理が行われます。getメソッドは、Vectorを戻すことにより結果を戻し、その結果には1つ以上のEntrySetが含まれます(詳細は「EntrySetの作成」を参照)。

18.3.4 EntrySetの作成

Oracle Virtual Directoryでは、ディレクトリの各オブジェクトはcom.octetstring.vde.Entryオブジェクトで表されます。各エントリには、オブジェクトの名前と属性値を持つ属性が含まれています。すべてのエントリ・オブジェクトは、com.octetstring.vde.EntrySetインタフェースの実装を使用してOracle Virtual Directoryで処理されます。エントリ・セットでは、特定のデータ・ソースから戻されたすべてのエントリが保存または処理されます。通常のOracle Virtual Directory処理では、検索リクエスト中に呼び出された各アダプタにより、Oracle Virtual Directoryから戻される結果のリストに独自のEntrySet実装が追加されます。また、プラグインにより、結果のVector配列に追加のEntrySetオブジェクトが挿入される場合もあります。検索リクエストを実行するためにすべてのアダプタへの問合せが完了すると、各EntrySetはクライアントに送信されるエントリに関して調査されます。

すべてのアダプタでEntrySet実装が作成されますが、プラグインでもEntrySetインタフェースのインスタンスが作成され、それを使用して検索リクエスト中にクライアントにエントリが戻されます。

次に、EntrySetの作成にプラグインで使用できる2つの方法を示します。

18.3.4.1 ExtensibleEntrySet

EntrySetの作成にプラグインで使用できる最も簡単な方法は、com.octetstring.vde.backend.extensible.ExtensibleEntrySetクラスを使用して、Entryオブジェクトのjava.util.Vectorに基づくEntrySetを作成する方法です。次にその手順を示します。

  1. 新規のjava.util.Vector配列を作成します。

  2. VectorにすべてのEntryオブジェクトを追加します。

  3. コンストラクタに前述のVectorを渡すExtensibleEntrySetの新規インスタンスを作成します。

例18-5は、Webサービスを使用して銘柄記号に基づいて株価を取得するプラグインの例を示しています。このプラグインは、カスタム・アダプタの概念を実装するように設計されています。それは、それ自体は機能を持たないアダプタであり、かわりにその機能を実装するようにアダプタ・レベルのプラグインを構成できるプレースホルダです。このStock Serviceの例では、プラグインはカスタム・アダプタに対して構成されます。このプラグインによってすべてのイベントの処理が行われるため、Stock Serviceプラグインによってchain.getNext()メソッドは呼び出されないことが想定されます。

プラグインのgetメソッドにより、VectorにEntryオブジェクト(株価エントリ)のリストが追加され、そのVectorに基づいてExtensibleEntrySetが作成されます。

例18-5 ExtensibleEntrySetを使用したEntrySet作成の例

public void get(Chain chain, Credentials creds, DirectoryString base,
            Int8 scope, Filter filter, Bool typesonly, Vector attributes,
            Vector result) throws DirectoryException, ChainException {

     // Since this method is a handler, chain.getNext is not called.

     if (scope.intValue() == SearchScope.BASEOBJECT && base.equals(this.suffix)) {
           // handle the logical root of the adapter
           Entry root = this.getSimpleEntry(this.suffix);
           Vector entries = new Vector();
           entries.add(root);
           result.add(new ExtensibleEntrySet(entries));
           return;
     }

     //This adapter only supports searches based on an equality match 
     //or an or'ing of equality matches
     if (filter.getSelector() != Filter.EQUALITYMATCH_SELECTED &&
           filter.getSelector() != Filter.OR_SELECTED) {
           throw new DirectoryException("Only equality match or an or'ing "+
     "of equality matches are allowed");
     }

     Vector entries = new Vector();

     //If the filter is an OR filter, we can iterate over every quote
     if (filter.getSelector() == Filter.OR_SELECTED) {
           Iterator it = filter.getOr().iterator();
           while (it.hasNext()) {
                 Entry entry = getStockEntry((Filter) it.next());
                 if (entry != null) {
                    entries.add(entry);
                 }
           }
     } else {
            //single quote            
            Entry entry = getStockEntry(filter);
            if (entry != null) {
                  entries.add(entry);
            }
    }
    //We use the ExtensibleEntrySet as a simple holder for entry sets.
    result.add( new ExtensibleEntrySet(entries));             
}

18.3.4.2 カスタムEntrySet

ExtensibleEntrySetを使用してEntrySetを作成するのは最も簡単な方法ですが、処理がクライアントに戻される前にすべての結果をコンパイルする必要があるため、最も効率のよい方法ではありません。この場合、フィルタの各項目に対するサービスがコールされます。このリクエストをより効率的に処理できるのは、LDAPアダプタ操作と同じように、Stock Serviceからリクエストされる時に新規エントリを取得してEntrySetsを作成する方法です。

LDAPアダプタのEntrySetに次のEntryが要求されると、システムにより、リモート・サーバーから一度に1つずつ次のエントリが取得されます。これは、LDAPプロトコルが意図する動作です。クライアントはすべてのエントリが処理される前にエントリの取得を開始できるため、この方法ははるかに効率的です。また、この方法では、クライアントによるエントリ取得の停止や、問合せの中断も可能です。

プラグインがリクエストどおりにエントリを戻すEntrySetを作成するためには、com.octetstring.vde.EntrySetの実装を作成する必要があります。各EntrySetで、次のメソッドを実装する必要があります。

  • boolean hasMore()

    EntrySetに他のエントリがある場合にtrueを戻します。このメソッドにより悪い影響が出ないように注意する必要があります。

  • Entry getNext()

    EntrySetの次のエントリを戻します。他にエントリがない場合にはNULLを戻します。

  • void cancelEntrySet()

    このメソッドは、EntrySetを完全に実行できない場合に呼び出されます。これにより、カスタムのEntrySet実装が保持しているシステム・リソースが解放されます。

例18-6は、株価を表示するWebサービスからアダプタを作成する例18-5と同じプラグインの実装ですが、例18-6では、getメソッドにより、カスタムEntrySetに渡される記号のリストのみが作成されます。例18-6のgetメソッドにより、VectorにEntryオブジェクト(株価エントリ)のリストが追加され、そのVectorに基づいてExtensibleEntrySetが作成されます。

例18-6 カスタムのEntrySetへの引渡しを行うサンプルのgetメソッド

public void get(Chain chain, Credentials creds, DirectoryString base,
            Int8 scope, Filter filter, Bool typesonly, Vector attributes,
            Vector result) throws DirectoryException, ChainException {
     if (scope.intValue() == SearchScope.BASEOBJECT && base.equals(this.suffix)) {
            Entry root = this.getSimpleEntry(this.suffix);
            Vector entries = new Vector();
            entries.add(root);
            result.add(new ExtensibleEntrySet(entries));
            return;
     }

     //This adapter only supports searches based on an equality match 
//or an or'ing of equality matches
     if (filter.getSelector() != Filter.EQUALITYMATCH_SELECTED &&
 filter.getSelector() != Filter.OR_SELECTED) {
     throw new DirectoryException("Only equality match or an or'ing"+
                                  " of equality matches are allowed");
     }

     String rdn="uid";
     ArrayList symbols = new ArrayList();
     //If the filter is an OR filter, we can iterate over every quote
     if (filter.getSelector() == Filter.OR_SELECTED) {
           Iterator it = filter.getOr().iterator();
           while (it.hasNext()) {
                     //Extract the symbol from the filter
                  String symbol = new String(filter.getEqualityMatch().
                  getAssertionValue().toByteArray());

                  //The attribute being checked in the equality search
                  //doesn't really matter, but we need an RDN for each entry
                  rdn = new String(filter.getEqualityMatch().
                  getAttributeDesc().toByteArray());
                  symbols.add(symbol);
           }
     } else {
            //single quote
            //Extract the symbol from the filter
            String symbol = new String(filter.getEqualityMatch().
            getAssertionValue().toByteArray());

           //The attribute being checked in the equality search doesn't
           //really matter, but we need an RDN for each entry
           rdn = new String(filter.getEqualityMatch().
                 getAttributeDesc().toByteArray());
           symbols.add(symbol);
       }

       //We use the ExtensibleEntrySet as a simple holder for entry sets.
       result.add( new StockEntrySet(symbols.iterator(),rdn,this.base));

}

例18-6では、銘柄記号のリストは、検索フィルタのorを反復することによって作成されています。コンパイルされたリストは、例18-7に示すカスタムのEntrySet実装に渡されます。

例18-7 カスタムのEntrySetに渡されるデータの例

public class StockEntrySet implements EntrySet {

       Iterator quotes;
       String rdn;
       String base;

       public StockEntrySet(Iterator quotes, String rdn,String base) {
              this.rdn = rdn;
              this.quotes = quotes;
              this.base = base;
       }

       public Entry getNext() throws DirectoryException {
              Entry entry = this.getStockEntry((String) quotes.next());
              if (entry == null) {
                    if (this.hasMore()) {
                          return this.getNext();
                    } else {
                          return null;
                    }
              } else {
                     return entry;
              }
       }

       public boolean hasMore() {
              return quotes.hasNext();
       }

       /**
       * Returns an entry for a stock quote
       * @param filter
       * @return An entry for the stock quote, or null for none.
       * @throws DirectoryException
       */
       public Entry getStockEntry(String symbol) throws DirectoryException {
       //Create a new entry with the symbol as the RDN
            Entry entry = new Entry(new DirectoryString(rdn + "=" + symbol + "," +
 this.base));

       //This uses an Apache Axis generated client stub
       NetXmethodsServicesStockquoteStockQuoteService service = new
       NetXmethodsServicesStockquoteStockQuoteServiceLocator();
       try {
            NetXmethodsServicesStockquoteStockQuotePortType 
            quoteService = service.
                 getNetXmethodsServicesStockquoteStockQuotePort();
            double value = quoteService.getQuote(symbol);
            if (value == -1) {
                  return null;
            }

            //Create the attribute for the entry
            Vector vals = new Vector();
            vals.add(new DirectoryString(symbol));
            entry.put(new DirectoryString(rdn),vals);

            vals = new Vector();
            vals.add(new DirectoryString("top"));
            vals.add(new DirectoryString("stockForOrganization"));
            entry.put(new DirectoryString("objectClass"),vals);

            vals = new Vector();
            vals.add(new DirectoryString(Double.toString(value)));
            entry.put(new DirectoryString("quote"),vals);

            return entry;

       } catch (ServiceException e) {
             throw new DirectoryException("Could not load web service : " +
 e.getMessage());
       } catch (RemoteException e) {
            throw new DirectoryException("Could not load web service : " +
 e.getMessage());
       }
}
    public void cancelEntrySet() {
    // nothing to do
    }
}

例18-7のEntrySet実装では、現在どの記号が処理されているかを追跡するjava.util.Iteratorが使用されています。StockEntrySetクラスでは、クライアントのかわりにOracle Virtual DirectoryによってEntryがリクエストされるまで、エントリ結果作成のためにWebサービスが呼び出されることはありません。

プラグインでは、1つ以上の株式の検索がサポートされているため、すべての検索で有効な結果が戻されるとはかぎりません。株式のリストを完全に検索し終わる前に、getNextでOracle Virtual DirectoryにNULLという結果が戻され、Oracle Virtual Directoryで結果が空であるとみなされる場合について考えてみます。この状況に対処するために、getNextには、getStockEntryの呼出しの後に特別なコード・ブロックが追加されています。getStockEntryNULLが戻され、リクエストされた株式の反復が終了していない場合には、次の候補を処理するためにgetNextによりそれ自身が呼び出されます。この再帰は、有効な結果が1つ以上戻されるか、すべての問合せが完了するまで続きます。

18.3.5 フィルタ処理の概要

LDAPフィルタ処理は複雑になる場合もあります。Oracle Virtual Directoryプラグインのコンテキストでは、前処理または後処理の際の2度、フィルタの解析に役立ちます。どちらの方法にもそれぞれのメリットとデメリットがあり、必ずしも相互に排他的であるとはかぎりません。

後処理のフィルタ処理

後処理のフィルタ処理では、結果として戻されるエントリが必要なフィルタに一致するかどうかが、com.octetstring.vde.util.FilterUtils.evalFilter(Entry e, Filter f)メソッドを使用して確認されます。これはフィルタを処理する最も簡単な方法で、Entryオブジェクトの集合としてメモリーに残る事前定義済の少量のデータ・セットを処理する際に便利です。一般的に、フィルタを別の形式(SQLのWHERE句や外部APIの特別なオブジェクト・モデルなど)に変換する必要がある場合には、このメソッドは適していません。

前処理のフィルタ処理

前処理フィルタはフィルタの解析に使用され、解析したフィルタを変更された検索に適用するか、検索ターゲットが解釈できる別の形式に変換する際に使用されます。LDAPフィルタをSQLのWHERE句に変換する前処理のフィルタについて考えてみます。これを実行するには、フィルタ・オブジェクトを調査する必要があります。たとえば、次のLDAPフィルタをSQLのWHERE句に変換するとします。

(&(|(user=jsmith)(user=lswanson)(user=ccarson))(dept=payroll)) 

前のLDAPフィルタには、ユーザーがjsmith、lswansonまたはccarsonで部門がpayrollのすべてのレコードと指定されています。図18-1に、このLDAPフィルタを図で示します。

図18-1 サンプルのLDAPフィルタの図

LDAPフィルタの図

図18-1のフィルタをSQLのWHERE句に変換するには、ツリーを調査する再帰関数を使用します。Oracle Virtual Directoryでは、この例のフィルタはFilterオブジェクトの階層として表され、これらには、調査可能なツリーを作成するための他のFilterオブジェクトのコレクションが含まれています。図18-1のフィルタには、図18-2に示すオブジェクト・モデルが含まれます。ここでは、フィルタ要素を表すために使用されているクラス名を、操作または演算子の下に示しています。

図18-2 フィルタのオブジェクト・モデルの例

オブジェクト・モデルの例

図18-2に示されているツリーを調査するために、フィルタのgetSelector()メソッドに問い合せてフィルタのタイプを判断する再帰メソッドが使用されます。フィルタのタイプが判明したら、getFilterTypeメソッドを使用してその値を抽出する必要があります。たとえば、フィルタがuser=jsmithなどの等価フィルタの場合、フィルタ・オブジェクトの値はcurrentFilter.getEqualityMatch()から取得します。この場合の戻り値はAttributeValueAssertionで、属性名および値がOracleとして保存されます。取得したら、値は文字列オブジェクトに変換できます。Filter_andおよびFilter_orオブジェクトは、操作中の子フィルタを反復するためのjava.util.Iteratorクラスを戻します。

LDAPフィルタでは、関連ごとに項目が2つに制限されるわけではありません。OR部分には3つのオペランドがあります。SQLで許可されているオペランドは操作ごとに2つのみであるため、図18-2のツリーはバイナリ・ツリーに変換する必要があります。

図18-3 OR機能の分割

OR機能の分割。

図18-3では、OR操作は、2つの別々のOR操作に分割されています。フィルタの最後のWHERE句は、((user=jsmith) OR ((user=lswanson) OR (user=ccarson))) AND (dept=payroll)です。LDAPの前置記法は、操作ごとに2つのオペランドのみを伴うSQLのLIKE中置記法に変換されています。例18-8に、変換のソース・コードを示します。

例18-8 LDAPの前置記法をSQLの表記法に変換するためのサンプルのソース・コード

import com.octetstring.vde.util.*;
import com.octetstring.ldapv3.*;
import java.util.*;

public class ConvertFilter {
    public static void main(String[] args) throws Exception {
        String ldapFilter = "(&(|(user=jsmith)(user=lswanson)" +
                                 (user=ccarson))(dept=payroll))";

        System.out.println("Ldap Filter : " + ldapFilter);
        System.out.println("SQL WHERE : " +
            filterToSQL(ParseFilter.parse(ldapFilter)));
    }
    /**
     *Converts an ldap filter to an SQL WERE clause
     *@param currentFilter The filter being converted
     */
public static String filterToSQL(Filter currentFilter) {
        String[] filterVal;
        String infix="";
        switch (currentFilter.getSelector()) {
            case Filter.EQUALITYMATCH_SELECTED :  // (attrib=val)
                 filterVal = getString(currentFilter.getEqualityMatch());
                 return filterVal[0] + "=" + filterVal[1]; 
                 
             case Filter.PRESENT_SELECTED : // (attrib=*)
                 return new String(currentFilter.getPresent().toByteArray()) +
                        "=*"; 
                  
             case Filter.GREATEROREQUAL_SELECTED : // (attrib>=val)
                 filterVal = getString(currentFilter.getGreaterOrEqual());
                 return filterVal[0] + ">=" + filterVal[1];

             case Filter.LESSOREQUAL_SELECTED :  // (attrib<=val)
                 filterVal = getString(currentFilter.getLessOrEqual());
                 return filterVal[0] + "<=" + filterVal[1]; 

             case Filter.SUBSTRINGS_SELECTED : // (attrib=val*ue)
                 filterVal = getString(currentFilter.getLessOrEqual());
                 return filterVal[0] + " LIKE " + filterVal[1];

             case Filter.AND_SELECTED : // &((attrib=val)(attrib2=val2))
                 Filter_and andFilter = currentFilter.getAnd();
                 
                 infix = "";
                 for (Iterator andEnum = andFilter.iterator();
                        andEnum.hasNext();) {
                    Filter aFilter = (Filter) andEnum.next();
                    infix += "(" + filterToSQL(aFilter) + ") AND ";  
                 }
                  
                 infix = infix.substring(0,infix.lastIndexOf("AND")) + " ";
                 return infix;

             case Filter.OR_SELECTED : // &((attrib=val)(attrib2=val2))
                 Filter_or orFilter = currentFilter.getOr();
                 infix = "";
                 for (Iterator orEnum = orFilter.iterator();orEnum.hasNext();)
                    {
                        Filter aFilter = (Filter) orEnum.next();
                    infix += " ( " + filterToSQL(aFilter) + " ) OR ";
                 }
                 infix = infix.substring(0,infix.lastIndexOf("OR")) + " ";
                 return infix;
                case Filter.NOT_SELECTED : // !(&((attrib=val)(attrib2=val2)))
                    return " NOT (" + filterToSQL(currentFilter.getNot()) + 
                            ") ";

                case Filter.APPROXMATCH_SELECTED : // (attrib~=val)
                    filterVal = getString(currentFilter.getApproxMatch());
                    return filterVal[0] + " LIKE " + filterVal[1];

                case Filter.EXTENSIBLEMATCH_SELECTED : //not standard
                    return ""; //not supported
        }
        
        //will never reach
        return "";
    }
    
    /**
      *Converts an AttributeValueAssertion to a two element array with the 
      *first being the attribute name and the second being the value
      */
    public static String[] getString(AttributeValueAssertion ava) {
        String matchAttr = new String(ava.getAttributeDesc().toByteArray());
        String matchVal = new  
                String(ava.getAssertionValue().toByteArray(),"UTF8");
        
        return new String[] {matchAttr,matchVal};
    }
}

18.3.6 クラスの概要

この項では、使用可能なOracle Virtual Directoryのクラスの高度な概要について説明します。Oracle Virtual Directoryのクラスの詳細は、『Oracle Fusion Middleware Java API Reference for Oracle Virtual Directory』(Javadoc)を参照してください。この項の内容は次のとおりです。

18.3.6.1 仮想サービス・インタフェース

仮想サービス・インタフェース(VSI)には、LDAPと同じようにOracle Virtual Directoryをコールするメソッドが用意されています。VSIは、コンテキストがグローバル・プラグインであるかアダプタ・レベルのプラグインであるかにかかわらず、同様に機能します。

チェーン内に3つのプラグインがあり、そのチェーンの1つ目のプラグインがVSIへのコールを実行する場合、2つ目および3つ目のプラグインにも出現するように、コールのコンテキストはOracle Virtual Directoryです。コールが2つ目のプラグインから実行された場合、コールは3つ目のプラグインのみを経由します。コールが3つ目のプラグインから実行された場合、プラグインがグローバルであるかローカルであるかにかかわらず、そのコールはどのプラグインも経由しません。プラグインがグローバルの場合、コールはOracle Virtual Directoryのルーティング・システムを経由してアダプタ・レベルのチェーンまで、グローバル・チェーンの外でも続行されます(ルーターによって1つ以上のアダプタが選択されているかどうかによります)。これにより、Oracle Virtual Directoryへのコールの一貫性が保証されるだけでなく、プラグインが自身をコールする無限ループからも保護されます。VSIは、各プラグイン・メソッドに渡されるチェーン・オブジェクトを使用して取得されます。

18.3.6.2 グローバル・サービス・インタフェース

グローバル・サービス・インタフェース(GSI)には、Oracle Virtual Directoryに対して、エンド・クライアントから実行されているようなLDAPに似たコールを行うメソッドが用意されています。各コールはアクセス制御システム(有効な場合)を介して処理され、ルーターによって操作に適切なアダプタを選択することが可能になります。GSIは、LDAPリスナーやWebゲートウェイが通信に使用するのと同じインタフェースです。

GSIは、chain.getVSI().getGSI()を呼び出すことでVSIを使用して取得できます。このハンドルを使用すると、addbinddeletegetgetByDNmodifyおよびrenameメソッドを呼び出せます。


警告:

GSIでは、現在のプラグインの前にあるコンテキストをコールすると、プラグインが無限ループに捕捉される場合があります。これにより、プラグイン・コードが繰り返しコールされ、予期しない結果を招く原因になる可能性があります。意図的に発生させる場合を除き、プラグインがスタックを遡ってコールし、ループが発生する可能性のあるシナリオには注意してください。一般的に、特定のアダプタをコールする必要がある場合を除き、VSIを使用するのが最も安全です。

Oracle Virtual Directoryには、ループ検出メカニズムは用意されていません。スタックのオーバーフローまたはメモリー不足が原因によるOracle Virtual Directoryとカスタム・プラグインとのクラッシュが検出された場合、これが原因である可能性が高いです。


18.3.6.3 アダプタ・サービス・インタフェース

アダプタ・サービス・インタフェース(ASI)には、ルーター・レベルにおいて、または特定のアダプタに対して直接、LDAPと同じようにOracle Virtual Directoryをコールするメソッドが用意されています。Oracle Virtual Directoryの結合ビュー・アダプタおよびそのジョイナでは、検索および結合の対象であるアダプタとの通信にASIが使用されます。ASIインタフェースは、プラグイン・クラスの検索情報を提供するために構成された場合など、内部アダプタから情報を取得する際に便利です。

ASIは、chain.getVSI().getASI()を呼び出すことでVSI経由で取得されます。このハンドルを使用すると、addbinddeletegetgetByDNmodifyおよびrenameメソッドを呼び出せます。各メソッドには、アダプタ名のパラメータを指定するものと指定しないものの2種類があります。アダプタ名が指定されているメソッドを使用して特定のアダプタを選択するか、その他の任意のメソッドを使用して、ルーターがルーティング・ロジックおよびルーティング構成に基づいて適切なアダプタを選択するようにします。


警告:

ASIでは、現在のプラグインの前にあるコンテキストをコールすると、プラグインが無限ループに捕捉される場合があります。これにより、プラグイン・コードが繰り返しコールされ、予期しない結果を招く原因になる可能性があります。意図的に発生させる場合を除き、プラグインがスタックを遡ってコールし、ループが発生する可能性のあるシナリオには注意してください。一般的に、特定のアダプタをコールする必要がある場合を除き、VSIを使用するのが最も安全です。

Oracle Virtual Directoryには、ループ検出メカニズムは用意されていません。スタックのオーバーフローまたはメモリー不足が原因によるOracle Virtual Directoryとカスタム・プラグインとのクラッシュが検出された場合、ループが原因である可能性が高いです。


VSI、GSIおよびASIのいずれも共通のインタフェースを共有しており、追加機能が用意されているインタフェースもあります。詳細は、『Oracle Fusion Middleware Java API Reference for Oracle Virtual Directory』を参照してください。

次のリストでは、サポートされているASIメソッドを説明します。

  • add()

    LDAPの追加操作を実行します。このメソッドには2つのバージョンがあり、Oracle Virtual Directoryルーターによるターゲット・アダプタの選択、または特定のアダプタの選択が可能です。

  • bind()

    LDAPのバインド操作を実行します。Oracle Virtual Directoryルーターによるアダプタの選択、または特定のアダプタの適用が可能です。

  • delete()

    LDAPの削除操作を実行します。Oracle Virtual Directoryルーターによるアダプタの選択、または特定のアダプタの適用が可能です。

  • get()

    LDAPの取得操作を実行し、これにより、Oracle Virtual Directoryルーターが適切なアダプタを選択できます。このgetメソッドは、EntrySet値のjava.util.Vectorを戻します。EntrySetは、問合せが行われたアダプタごとに含まれます。

  • getbyDN()

    特定のDNを使用してLDAPベースの検索を実行する便利なメソッドです。コール元は、選択して特定のアダプタを指定するか、Oracle Virtual Directoryルーターによる選択を行います。

  • modify()

    LDAPの変更操作を実行します。コール元は、特定のアダプタを指定するか、ルーターによる自動選択を選択します。

  • rename()

    LDAPの名前変更操作を実行します。コール元は、特定の送信元および宛先アダプタを指定するか、ルーターによる自動選択を選択します。

18.3.6.4 ジョイナ

Oracle Virtual Directoryの結合ビュー・アダプタではジョイナを使用して、特定のアダプタからのエントリを結合し、プライマリ・アダプタのエントリとマージします。ジョイナは、新しいジョイナの実装に必要な基本的な操作やメソッドを定義する抽象クラスです。ジョイナは、結合済のエントリに対して操作を実行する必要がある場合に結合ビュー・アダプタによりコールされます。ジョイナは、LDAP操作前のデータ操作を可能にする事前アクション操作を定義します。また、コールされる操作に応じて、ジョイナによるターゲット結合アダプタ内のターゲット・エントリの選択を可能にするmapOperationTargetByEntryメソッドも定義します。

ジョイナは、プライマリ・アダプタおよびターゲット・アダプタとともにインスタンス化されます。結合ビュー・アダプタは常にプライマリ・アダプタのコンテキスト内で機能し、マッピングや操作をターゲット結合アダプタで実行する必要がある場合にジョイナ・メソッドを呼び出します。

結合ビュー・アダプタの取得操作により、プライマリ・アダプタの結果のみに基づいてJoinEntrySetが作成されます。続いてOracle Virtual DirectoryクライアントがOracle Virtual Directoryの結果をポーリングすると、JoinEntrySetクラスによりジョイナJoinByEntryメソッドが呼び出され、結合アダプタへのコールとエントリ結果のマージが行われます。複数の結合関係が構成されている場合、定義されているすべての関係に基づいてエントリが完全に結合されるまで、エントリ・セットの処理はすべての結合をループします。

ジョイナ・コンストラクタ・メソッドは、結合ビュー・アダプタによってジョイナがインスタンス化される際に呼び出されます。この状況は、最初のLDAP操作が(遅延構成という形で)結合ビュー・アダプタによって処理されるまで発生しません。コンストラクタは、関連するターゲット・アダプタ名とともに、構成ファイルのジョイナの構成パラメータに渡されます。

createJoinFilterメソッドは、一般的にはローカル・メソッドで、AdapterServiceInterfaceへの後続のコール用に検索フルターを作成するためにJoinByEntryメソッドによって呼び出されます。

18.3.6.5 ユーティリティ・クラス

Oracle Virtual Directoryでは、次のユーティリティ・クラスがサポートされます。

  • PluginUtils

    このクラスは、renameAttributecopyAttributeなどを含むマッピング機能の基本的なツールボックスです。通常、これらのクラスは、マッピング・スクリプトで使用されますが、Javaプラグインでも使用できます。

  • FilterTools

    このクラスには、LDAP検索フィルタを作成および操作するためのメソッドがあります。

  • ParseFilter

    ParseFilterクラスには、文字列とフィルタを相互に変換する機能があります。

  • DNUtility

    このクラスには、個々のDN名コンポーネントの操作を可能にするDNの展開や作成など、DN操作ルーチンが用意されています。

  • LDAPResult

    LDAPResultは、Int8値を戻す任意のメソッドから戻される結果の比較に使用できるユーティリティ・クラスです。これらの定数は、結果コードのLDAPエラー・コードへの変換に便利です。

  • VDELogger

    Loggerクラスには、Oracle Virtual Directoryロギング・ファシリティ(Log4J)へのインタフェースがあります。このクラスを使用して、コンソールまたは監査メッセージをOracle Virtual Directoryのメッセージと統合します。

  • PasswordEncryptor

    このクラスには、文字列値をCrypt、SHA、SSHAなどの様々なハッシュ形式に暗号化する多様なメッソドがあります。

18.3.6.6 データ・クラス

Oracle Virtual Directoryでは、次のユーティリティ・クラスがサポートされます。

  • Attribute

    Attributeは、Entryクラスとともに使用される基本的なオブジェクトです。Attributeでは(属性名などの)タイプが定義され、その値が含まれます。また、クローニングおよび等価テスト用のメソッドが用意されています。

  • Credentials

    セッションの資格証明を保持する基本的なオブジェクト。このオブジェクトには、IPアドレス、binddnおよびパスワード(必要な場合)が含まれます。通常、AdapterServiceInterfaceに関連する多くの操作では、関連するのはbinddnのみです。

  • エントリ

    このオブジェクトは、LDAPエントリおよびLDAPの変更リクエストなどの部分エントリの保持に使用されます。多くの場合、FilterToolユーティリティをこれらのオブジェクトと組み合せてフィルタをテストします。

  • EntryChange

    このオブジェクトには、LDAP変更項目が含まれます。変更リクエストを処理する際には、通常、EntryChangeオブジェクトのVectorがAdapterServiceInterfaceに渡されます。各EntryChangeには、単一エントリへの単一の変更が含まれます。

  • EntrySet

    EntrySetには、アダプタからの一連の問合せ結果が含まれます。メソッドが最初にEntrySetを受け取る際には、エントリの結果セットがメモリーに存在しない場合があります。getNextメソッドを呼び出すことで、EntrySetから一意のEntryオブジェクトが戻されます。getNextが呼び出されるたびに、関連するアダプタまたはプラグイン・クラス・コードが呼び出され、存在する場合には次のEntryが取得されます。他のエントリの可用性をテストするには、hasMore()メソッドを使用します。


    ヒント:

    結果セット全体を処理する場合以外は、getNext()を直接呼び出さないようにしてください。LDAPクライアントから呼出しを実行することをお薦めします。Oracle Virtual Directoryプラグイン・クラスの場合には、特別なメソッドpostSearchEntry()が用意されており、クライアントに戻される際に各エントリを変更できます。アダプタから到着するたびにエントリを処理するのではなく、Oracle Virtual Directoryで結果セット全体を一度にロードするなど、不必要にgetNext()を呼び出すと、メモリーの過剰な使用およびパフォーマンス低下の原因になる可能性があります。

  • Filter

    Filterオブジェクトは、標準のLDAPフィルタを表します。このオブジェクトには、LDAPフィルタの設定、テストおよび比較に便利なメソッドがあります。Filterオブジェクトには、その他のフィルタ・オブジェクトの階層(Filter_andFilter_orなど)が含まれる場合もあります。

  • LDAPURL

    このクラスには、標準のLDAPURLを解析または作成するためのメソッドがあります。

18.3.6.7 データ型

Oracle Virtual Directoryでは次のデータ型をサポートしています。

  • BinarySyntax

    パスワードまたはユーザー証明書などの任意のバイナリ値。

  • DirectoryString

    大/小文字が区別されない文字列。

  • IASString

    大/小文字が区別される文字列。

  • IntegerSyntax

    整数値。

  • DistinguishedName

    識別名の値(比較はDN等価ルールに準拠します)。

18.3.6.8 例外

Oracle Virtual Directoryでは、次の例外がサポートされます。

  • DirectoryBindException

    バインドに失敗した場合にスローされる例外。

  • DirectoryException

    すべてのディレクトリ・エラー時にスローされる一般的な例外。詳細はgetMessage()を参照してください。LDAPエラー・コードを確認する場合はgetLDAPErrorCode()を参照してください。この例外は、アダプタまたは別のプラグインによって生成されることがあります。

  • DirectorySchemaViolation

    リモート・スキーマまたはローカル・スキーマに違反するエントリの追加や変更が試行されると、スキーマ違反が発生します。

  • InvalidDNException

    InvalidDNExceptionは、無効なDNがパラメータとして渡されるとオブジェクトおよびユーティリティによってスローされます。

18.4 Oracle Virtual DirectoryへのWebサービス・クライアントの接続

Oracle Virtual Directoryが最初にリリースされたときは、LDAPがアイデンティティ・プロファイル情報にアクセスするための主要なプロトコルでした。LDAPは、認証および認可については依然として主要なプロトコルですが、新しいアプリケーションは、多くの場合、SOAPまたはREST標準に基づいたWebサービスを使用して構築されます。Oracle Virtual Directoryは、デフォルトでこれらの要件を満たすメカニズムを提供します。

RESTベースのクライアント(簡単に言えば、HTTP POSTを送信してデータを取得するクライアント・アプリケーション)は、Oracle Virtual DirectoryのWebゲートウェイによって処理されます(付録C「HTTPリスナーのWebゲートウェイ・サービス」を参照)。

かわりに、Oracle Virtual DirectoryのDSMLv2サービスを使用できます。これは、オラクル社によるDSMLv2標準の実装です。DSMLは、最初はLDAPデータのXML表現(基本的にASCIIベースのLDIFの代替)を提供するために作成されました。DSMLv2によってSOAPベースのWebサービスが追加されました。

このSOAPベースのWebサービスは、HTTPリスナーでDSMLv2サービスを有効にするとOracle Virtual Directoryで使用可能になります。URLは次のとおりです。

http://ovdserver:httpport/services/dsmlv2/service

DSMLはOASIS標準化団体によって定義済の標準であり、SOAPベースのサービスですが、残念ながら公式のWSDLファイルは作成されたことがありません。WSDLファイルは、SOAPベースのWebサービスで使用されるドキュメントであり、それらのサービスをクライアント・アプリケーションに説明し、アプリケーションでどのメソッドをコールするかを判断できるようにするものです。

ただし、サード・パーティによってWSDLファイルが開発されており、次のサイトから入手できます。

http://www.users.globalnet.co.uk/~jonbek/EASBlogLinks/dsmlQuery_v3.wsdl

認証の概要

Oracle Virtual DirectoryのDSMLv2サービスでは、ACL、ルーティング・ルールなどのOracle Virtual Directoryのセキュリティ・セマンティクスのすべてが適用されます。

アプリケーションは、HTTP Basic認証を使用してDSMLv2サービスを認証します。HTTP Basic認証では、Oracle Virtual DirectoryのWebゲートウェイで使用される.htaccessファイルは使用されません

資格証明をDSMLv2サービスに送信するには、SOAPクライアントは次の値を含むHTTP認証ヘッダーを送信する必要があります。

base64-encoded-dn:base64-encoded-password

たとえば、ユーザーがcn=orcladminであり、パスワードがwelcome1である場合、資格証明は次のようになります。

Y249b3JjbGFkbWlu:d2VsY29tZTE=

この文字列も、Base64でエンコードされている必要があり、完全なヘッダーは次のようになります。

Authorization: Basic WTI0OWIzSmpiR0ZrYldsdTpkMlZzWTI5dFpURT0=

有効なDNまたは資格証明を指定するかぎり、LDAPクライアントを経由してOracle Virtual DirectoryにアクセスしているかのようにOracle Virtual Directoryのセキュリティが使用されます。