Saturday, January 4, 2014

JNDI 以外のものを使って LDAP 関連のことを

あけましておめでとうございます。 仕事中にさぼって書いています。

LDAP サーバーを利用するコードを Java で書くとしたら, たぶん JNDI を利用するケースが多いんだろうなと思います。 とはいえ, JNDI 自体は LDAP の取り扱いに特化した API というわけではありませんので, そうとは気づかずにさわりはじめると, 最初のうちは戸惑います。 たとえば DirContextbind とか unbind とかのメソッドは, LDAP における BIND や UNBIND とはまったく別の意味を持っています。 また, JNDI を使って LDAP 関連のコードを書こうとすると, Hashtable とか Enumeration とかが視界に入ってくるというのも, やや苦しいところです。

そもそも, JNDI 以外の LDAP 用のクライアントライブラリには, どんなものがあるでしょう。 今回, Apache Directory LDAP APIUnboundID LDAP SDK for Java を, 少しだけさわってみました。

Apache Directory LDAP API

Apache Directory LDAP API は, 依存する外部ライブラリが少なくないのが, やや気になるところです。 ログのために SLF4J を, NIO のために Apache MINA を, そのほか Commons 何々などなどを利用しているので, クラスパスに置く必要のある JAR ファイルがやや多くなってしまいます。 ただ, 少しさわってみたうえでの第一印象としては, ドキュメント がわかりやすく書かれており, まずまず使いやすそうに見えました。

最も単純な BIND および UNBIND をやってみます。 LDAP サーバーと接続を開き, BIND をおこない, UNBIND をおこない, そして接続を閉じるというものです。

        LdapConnection conn = new LdapNetworkConnection("192.168.1.1", 389);
        try {
            conn.connect();
            conn.bind("cn=Manager,dc=localdomain", "secret");
            conn.unBind();
        } catch (LdapException e) {
            // ...
        } finally {
            try {
                conn.close();
            } catch (IOException e) {
                // ....
            }
        }

connect メソッドで接続を開き, bind メソッドで BIND をおこない, unBind メソッドで UNBIND をおこない, そして close メソッドで接続を閉じます。 非常に直感的でわかりやすいと感じます。 ちなみに, もし匿名バインドをおこないたいなら,

            conn.bind("", "");

もしくは,

            conn.bind();

と書くことができます。

ところで, ソースコードを眺めてみますと, bind メソッドは, もしまだ接続が開かれていなければ, まず内部で connect メソッドを呼び出しているようですので, 上記のコードでは connect メソッドの呼び出しを省略しても構わないかもしれません。 それに対して, unBind メソッドは, UNBIND リクエストを LDAP サーバーに送った後に接続を閉じるということ (FIN を送って ACK を受け取ること) をおこなってはいますが, close メソッドと同じことをすべておこなっているわけではなく, 使用済みソケットを廃棄するところまではおこなっていないように見えなくもないので, 上記のコードで close メソッドの呼び出しを省略してよいものかどうか, ちょっとよくわかりません。

なお, 各メソッドのうち, close メソッドは IOException をスローする可能性があり, それ以外は LdapException をスローする可能性があります。 LdapException のサブクラスには LdapOperationException というものがあり, そこには getResolvedDngetResultCode というメソッドが定義されていますので, BIND などのオペレーションの結果に応じていろいろ処理を分岐する必要がある場合に, ちょっと便利かもしれません。

UnboundID LDAP SDK for Java

UnboundID LDAP SDK for Java は, 依存する外部ライブラリが特になく, その点は Apache Directory LDAP API よりもデリバリーしやすいと言えるかもしれません。 ドキュメント は, LDAP というプロトコル自体について幅広く知っていないとやや理解が難しいんじゃないかという印象を持ちました。 (というか, 自分自分の読解力不足を棚に上げて, そういう言い訳をしたいだけだったりもしますけれど。) それから, ログは JUL (java.util.logging) を利用しているようです。

それでは, こちらも単純な BIND および UNBIND をやってみましょうか。 次のようになりました。

        LDAPConnection conn = null;
        try {
            conn = new LDAPConnection("192.168.1.1", 389);
            conn.bind("cn=Manager,dc=localdomain", "secret");
        } catch (LDAPException e) {
            // ...
        } finally {
            if (conn != null)
                conn.close();
        }

LDAPConnection インスタンスを作成する段階で LDAP サーバーとの接続を開くことがおこなわれ, また close メソッドで接続を閉じる際には UNBIND もあわせておこなわれますので, Apache Directory LDAP API に比べれば, さらにコードはコンパクトになっています。 ちなみに, 匿名バインドをおこないたいなら,

            conn.bind("", "");

と書くことができます。

Apache Directory LDAP API と違って IOException を気にする必要がないというのは, ちょっとうれしい気もします。 また, LDAPException には, getMatchedDNgetResultCode だけでなく, いくつか便利そうなメソッドが定義されています。 Apache Directory LDAP API の LdapException (というか, そのサブクラスの LdapOperationException) は, JNDI の NamingException と同様にエラーコードに応じて多数のサブクラスを用意するというアプローチですが, UnboundID LDAP SDK for Java の LDAPException は, あまりサブクラスを増やさず, なるべくこのクラスだけでいろいろなことを扱うことにするというアプローチのようです。

感想

たまたま, ぜんぜん別の話題を探しているときに, LDAP Java library - Stack Overflow (Dec 23, 2008) という投稿を見かけたのが, 今回のきっかけでした。 まだ, BIND と UNBIND しかやっていなくて, どちらがいいかというのは全く言えませんが, 入門レベルで取り付きやすそうなのは Apache のほうで, より高度なことを期待するなら UnboundID といったところなのでしょうか。

No comments:

Post a Comment