基本的な使い方

このセクションでは、Spring LDAP の使用の基本について説明します。次の内容が含まれます。

AttributesMapper を使用した検索とルックアップ

次の例では、AttributesMapper (Javadoc) を使用して、すべての人物オブジェクトのすべての共通名のリストを作成します。

例 1: 単一の属性を返す AttributesMapper 
import static org.springframework.ldap.query.LdapQueryBuilder.query;

public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;

   public void setLdapClient(LdapClient ldapClient) {
      this.ldapClient = ldapClient;
   }

   public List<String> getAllPersonNames() {
      return ldapClient.search()
                .query(query().where("objectclass").is("person"))
                .toList((Attributes attrs) -> (String) attrs.get("cn").get());
   }
}

AttributesMapper のインライン実装は、Attributes オブジェクトから必要な属性値を取得して返します。内部的に、LdapClient は見つかったすべてのエントリを繰り返し処理し、各エントリに対して指定された AttributesMapper を呼び出し、結果をリストに収集します。その後、リストは search メソッドによって返されます。

AttributesMapper 実装は、次のように完全な Person オブジェクトを返すように簡単に変更できることに注意してください。

例 2: Person オブジェクトを返す AttributesMapper
import static org.springframework.ldap.query.LdapQueryBuilder.query;

public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;
   ...
   private class PersonAttributesMapper implements AttributesMapper<Person> {
      public Person mapFromAttributes(Attributes attrs) throws NamingException {
         Person person = new Person();
         person.setFullName((String)attrs.get("cn").get());
         person.setLastName((String)attrs.get("sn").get());
         person.setDescription((String)attrs.get("description").get());
         return person;
      }
   }

   public List<Person> getAllPersons() {
      return ldapClient.search()
            .query(query().where("objectclass").is("person"))
            .toList(new PersonAttributesMapper());
   }
}

LDAP のエントリは、識別名 (DN) によって一意に識別されます。エントリの DN がわかっている場合は、クエリを実行せずにエントリを直接取得できます。これは、Java LDAP では「ルックアップ」と呼ばれます。次の例は、Person オブジェクトの検索を示しています。

例 3: Person オブジェクトになるルックアップ
public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;
   ...
   public Person findPerson(String dn) {
      return ldapClient.search().name(dn).toObject(new PersonAttributesMapper());
   }
}

前の例では、指定された DN を検索し、見つかった属性を提供された AttributesMapper に渡します。この場合、結果は Person オブジェクトになります。

LDAP クエリの構築

LDAP 検索には、次のような多くのパラメーターが含まれます。

  • ベース LDAP パス: 検索を開始する LDAP ツリー内の場所。

  • 検索の範囲: LDAP ツリーのどの深さまで検索するか。

  • 返す属性。

  • 検索フィルター: スコープ内の要素を選択するときに使用する条件。

Spring LDAP は、LDAP クエリを構築するための流れるような API を備えた LdapQueryBuilder (Javadoc) を提供します。

ベース DN dc=261consulting,dc=com から始まる検索を実行し、返される属性を cn および sn に制限し、(&(objectclass=person)(sn=?)) のフィルターを使用して、? を lastName パラメーターの値に置き換えたいとします。次の例は、LdapQueryBuilder を使用してそれを行う方法を示しています。

例 4: 検索フィルターを動的に構築する
import static org.springframework.ldap.query.LdapQueryBuilder.query;

public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;
   ...
   public List<String> getPersonNamesByLastName(String lastName) {

      LdapQuery query = query()
         .base("dc=261consulting,dc=com")
         .attributes("cn", "sn")
         .where("objectclass").is("person")
         .and("sn").is(lastName);

      return ldapClient.search().query(query)
            .toObject((Attributes attrs) -> (String) attrs.get("cn").get());
   }
}
複雑な検索パラメーターの構築を簡素化するだけでなく、LdapQueryBuilder とその関連クラスは、検索フィルター内の安全でない文字を適切にエスケープする機能も提供します。これにより、ユーザーがそのような文字を使用して不要な操作を LDAP 操作に挿入する「LDAP インジェクション」を防止できます。
LdapClient には、LDAP 検索を実行するためのオーバーロードされたメソッドが多数含まれています。これは、可能な限り多くの異なるユースケースとプログラミングスタイルの設定に対応するためです。ほとんどのユースケースでは、入力として LdapQuery を使用するメソッドを使用することをお勧めします。
AttributesMapper は、検索およびルックアップデータを処理するときに使用できる利用可能なコールバックインターフェースの 1 つにすぎません。代替については、DirContextAdapter による属性アクセスと操作の簡素化を参照してください。

LdapQueryBuilder の詳細については、高度な LDAP クエリを参照してください。

識別名を動的に構築する

識別名 ( LdapName (標準 Javadoc) (英語) ) の標準 Java 実装は、識別名の解析に関しては良好に機能します。ただし、実際に使用すると、この実装にはいくつかの欠点があります。

  • LdapName 実装は変更可能であり、ID を表すオブジェクトにはあまり適していません。

  • 変更可能な性質にもかかわらず、LdapName を使用して識別名を動的に構築または変更するための API は扱いにくいものです。インデックス付きまたは (特に) 名前付きコンポーネントの値を抽出するのも、少し厄介です。

  • LdapName の操作の多くは、チェック例外をスローします。通常、エラーが致命的であり、意味のある方法で修復できない状況では、try-catch ステートメントが必要です。

識別名の操作を簡素化するために、Spring LDAP は LdapNameBuilder (Javadoc) と、LdapName を操作するときに役立つ LdapUtils (Javadoc) の多数のユーティリティメソッドを提供します。

サンプル

このセクションでは、前のセクションで説明した内容の例をいくつか紹介します。最初の例では、LdapNameBuilder を使用して LdapName を動的に構築します。

例 5: LdapNameBuilder を使用して LdapName を動的に構築する
import org.springframework.ldap.support.LdapNameBuilder;
import javax.naming.Name;

public class PersonRepoImpl implements PersonRepo {
  public static final String BASE_DN = "dc=example,dc=com";

  protected Name buildDn(Person p) {
    return LdapNameBuilder.newInstance(BASE_DN)
      .add("c", p.getCountry())
      .add("ou", p.getCompany())
      .add("cn", p.getFullname())
      .build();
  }
  ...
}

Person に次の属性があるとします。

属性名 属性値

country

スウェーデン

company

いくつかの会社

fullname

誰か

上記のコードは、次の識別名になります。

cn=Some Person, ou=Some Company, c=Sweden, dc=example, dc=com

次の例では、LdapUtils を使用して識別名から値を抽出します。

例 6: LdapUtils を使用した識別名からの値の抽出
import org.springframework.ldap.support.LdapNameBuilder;
import javax.naming.Name;
public class PersonRepoImpl implements PersonRepo {
...
  protected Person buildPerson(Name dn, Attributes attrs) {
    Person person = new Person();
    person.setCountry(LdapUtils.getStringValue(dn, "c"));
    person.setCompany(LdapUtils.getStringValue(dn, "ou"));
    person.setFullname(LdapUtils.getStringValue(dn, "cn"));
    // Populate rest of person object using attributes.

    return person;
  }
}

1.4 を含む以前の Java バージョンではパブリック識別名の実装がまったく提供されなかったため、Spring LDAP 1.x は独自の実装である DistinguishedName を提供しました。この実装にはいくつかの欠点があり、バージョン 2.0 で廃止されました。ここで、LdapName を前述のユーティリティと共に使用する必要があります。

バインドとアンバインド

このセクションでは、データを追加および削除する方法について説明します。更新については、次のセクションで説明します。

データの追加

Java LDAP にデータを挿入することをバインディングと呼びます。LDAP 用語では、「バインド」はまったく別のものを意味するため、これはやや混乱します。JNDI バインドは LDAP 追加操作を実行し、指定された識別名を持つ新しいエントリを一連の属性に関連付けます。次の例では、LdapClient を使用してデータを追加します。

例 7: 属性を使用したデータの追加
public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;
   ...
   public void create(Person p) {
      Name dn = buildDn(p);
      ldapClient.bind(dn).attributes(buildAttributes(p)).execute();
   }

   private Attributes buildAttributes(Person p) {
      Attributes attrs = new BasicAttributes();
      BasicAttribute ocattr = new BasicAttribute("objectclass");
      ocattr.add("top");
      ocattr.add("person");
      attrs.put(ocattr);
      attrs.put("cn", "Some Person");
      attrs.put("sn", "Person");
      return attrs;
   }
}

手動属性構築は — 退屈で冗長ですが — 多くの目的に十分です。ただし、DirContextAdapter による属性アクセスと操作の簡素化に従って、バインド操作をさらに単純化できます。

データの削除

Java LDAP でのデータの削除は、バインド解除と呼ばれます。JNDI アンバインドは LDAP 削除操作を実行し、指定された識別名に関連付けられたエントリを LDAP ツリーから削除します。次の例では、LdapClient を使用してデータを削除します。

例 8: データの削除
public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;
   ...
   public void delete(Person p) {
      Name dn = buildDn(p);
      ldapClient.unbind(dn).execute();
   }
}

更新

Java LDAP では、rebind を使用する方法と modifyAttributes を使用する方法の 2 つの方法でデータを変更できます。

Rebind を使用した更新

rebind はデータを変更する荒っぽい方法です。基本的には unbind の後に bind が続きます。次の例では、LDAP の rebind を呼び出します。

例 9: rebind を使用した変更
public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;
   ...
   public void update(Person p) {
      Name dn = buildDn(p);
      ldapTemplate.bind(dn).attributes(buildAttributes(p)).replaceExisting(true).execute();
   }
}

modifyAttributes を使用した更新

データを変更するより洗練された方法は、modifyAttributes を使用することです。この操作は、次のように、明示的な属性変更の配列を受け取り、特定のエントリに対して実行します。

例 10: modifyAttributes を使用した変更
public class PersonRepoImpl implements PersonRepo {
   private LdapClient ldapClient;
   ...
   public void updateDescription(Person p) {
      Name dn = buildDn(p);
      Attribute attr = new BasicAttribute("description", p.getDescription())
      ModificationItem item = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr);
      ldapTemplate.modify().name(dn).attributes(item).execute();
   }
}

Attributes および ModificationItem 配列を構築するのは大変な作業です。ただし、DirContextAdapter による属性アクセスと操作の簡素化で説明しているように、Spring LDAP はこれらの操作を簡素化するためのより多くのヘルプを提供します。