Book: Javaを使ったLDAPアクセス -JNDI, Search-

JavaでLDAPにアクセスする方式は大きく分けて、LDAP SDKを使う方法と、JNDIを使ってアクセスする方法2種類があり、LDAP SDKにはいろいろな実装(OpenLDAP -Novel JLDAP-, Netscape,Mozilla LDAP Java SDKなど )があるが、開発が若干スローダウン気味です。(枯れていて安定しているという見方もできます。)

一方、JNDIのほうは、JDKとともに保守されているので、最新性が保たれているように感じられます。今回はJNDIを使ってアクセスしてみたいと思います。JNDI(Java Naming Directory Interface)は、LDAPに特化した仕様ではなく、Service Providerを切り替えれば、DNSやNIS、RMI、ファイルシステムなどからも情報を汎用的に操作できるようになる抽象化されたAPIです(個人的には抽象化により理解を困難にしている面もあると感じていますが・・・JDBCのようにうまくいっていないように感じますが、大きい構想のフレームワークなのでしょうがないのでしょう。)。LDAPのJNDI Service Provider("com.sun.jndi.ldap.LdapCtxFactory")はSunのJDK1.4から標準で付属してきます。

以下の例は、スタンドアローン(J2EEコンテナなしでもという意味)で動作する"uid=test*"というエントリを検索し、属性を表示する例です。

package ldapclient;

import java.util.Hashtable;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

/**
 * @see http://java.sun.com/developer/technicalArticles/Programming/jndi/index.h...
 * @author yyamazaki
 */
public class Main {

    public static void main(String[] args) {
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
        env.put(Context.PROVIDER_URL, "ldap://localhost:389");
        //env.put(Context.SECURITY_AUTHENTICATION, "simple");
        env.put(Context.SECURITY_PRINCIPAL, "cn=Directory Manager");
        env.put(Context.SECURITY_CREDENTIALS, "password");

        DirContext context = null;
        try {
            context = new InitialDirContext(env);
            
            //search entry.
            SearchControls searchControls = new SearchControls();
            searchControls.setSearchScope(SearchControls.SUBTREE_SCOPE);

            NamingEnumeration entries = context.search("dc=example,dc=com", "uid=test*", searchControls);

            while (entries.hasMore()) {
                SearchResult entry = (SearchResult) entries.next();
                System.out.println("dn: " + entry.getNameInNamespace());

                //Attributes in the entry.
                NamingEnumeration attributes = entry.getAttributes().getAll();
                while (attributes.hasMore()) {
                    Attribute attribute = (Attribute) attributes.next();

                    // Values in the attributes of the entry.
                    NamingEnumeration attributeValues = attribute.getAll();
                    while ( attributeValues.hasMore() ) {
                        System.out.print(attribute.getID() + ": ");
                        System.out.println(attributeValues.next());
                    }
                }
                System.out.println();
            }
        } catch (NamingException ex) {
            Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            if( context != null ){
                try {
                    context.close();
                } catch (NamingException ex) {
                    Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }
}
実行結果:
dn: uid=test.0,ou=People,dc=example,dc=com
mail: test.0@example.com
mail: test.0@example.net
uid: test.0
userPassword: [B@be2358
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
sn: test.0
cn: test.0

dn: uid=test.99,ou=People,dc=example,dc=com
mail: test.99@example.com
uid: test.99
objectClass: person
objectClass: organizationalPerson
objectClass: inetOrgPerson
objectClass: top
sn: test 99
cn: test
エントリのEnumeration、属性のEnumeration、値のEnumerationを処理するために3つのループがネストしており、あまりきれいにかけていませんが、一通り、値が取得できることは確認できます。 前にあげたPerlの例に比べると若干くどく感じられるのは、JavaといういうよりもJNDIの抽象化のせいかもしれません。 参考:Book: GlassFish: Custom ResourceによるJNDI使用した LDAP アクセスの例 http://www.knowd.co.jp/yamazaki/?q=node/140