2014年6月17日火曜日

Ruby/LDAP 経由で LDAPS 接続

Rubyから手軽にLDAP接続するのに使えるRuby/LDAPライブラリですが、LDAPS接続をする方法について、あまり実際の例がないように思います。今回、実際にやってみたので、ポイントを書いておこうと思います。

ポイントは3つ。
  • LDAP::Connの代わりにLDAP::SSLConnを使うこと。
  • 接続先ポート番号を明示的に指定すること。
  • LDAPクライアント用設定(/etc/ldap/ldap.conf)で証明書検証設定を正しく設定すること。
以下、やってみた時の経緯です。
今までSSLなしのLDAP接続はできていました。単にLDAP::Conn を LDAP::SSLConn に置き換えればいいと思っていたんですが、エラーになってしまいます。例をirbで示してみますと、こんな感じです。

irb(main):001:0> require 'ldap'
=> true

irb(main):003:0> conn = LDAP::SSLConn.new('localhost')
=> #<LDAP::SSLConn:0x000000021130d0>

irb(main):004:0> conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
=> #<LDAP::SSLConn:0x000000021130d0>

irb(main):006:0> conn.bind(‘cn=hoge,dc=foo,dc=localhost’,’pass')
LDAP::ResultError: Can't contact LDAP server
from (irb):6:in `bind'
from (irb):6
from /usr/bin/irb:12:in `<main>'

よく調べてみると、ポート番号があやしいことに気づきました。公式ドキュメントによると、デフォルト値が定数LDAP_PORTになっているんですが、LDAP::LDAP_PORTはSSLではない接続用のポート番号(389)が入った定数なのです。

実はLDAP::LDAPS_PORTの方がSSL接続用のポート番号(636)が入った定数なんですね。なぜデフォルト値がLDAPS_PORTじゃなくてLDAP_PORTなのかはよく分からないのですが、もしかして、LDAP::SSLConnはLDAP::Connのサブクラスだからかもしれません。※参考→http://ruby-ldap.sourceforge.net/rdoc/classes/LDAP/SSLConn.html

ということで、今度はポート番号にLDAP::LDAPS_PORTを指定して再試行してみます。

irb(main):008:0> conn = LDAP::SSLConn.new('localhost', LDAP::LDAPS_PORT)
=> #<LDAP::SSLConn:0x0000000211c180>

irb(main):009:0> conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
=> #<LDAP::SSLConn:0x0000000211c180>

irb(main):010:0> conn.bind('cn=admin,dc=test,dc=localhost','admin')
LDAP::ResultError: Can't contact LDAP server
from (irb):10:in `bind'
from (irb):10
from /usr/bin/irb:12:in `<main>’

しかし、まだ同じエラーです。slapd側のログを見ると、接続自体は確立されているようです。このようなログが残っています。

conn=1013 fd=13 TLS established tls_ssf=128 ssf=128

このログはポート番号修正前には記録されなかったので一歩前進です。LDAPのSSL接続について更に検索すると、こんな情報が見つかりました。→http://christian.hofstaedtler.name/blog/2009/05/ruby-ldap-ssl.html

要するに/etc/ldap/ldap.confにクライアント設定が原因かもしれないということ。試しに、/etc/ldap/ldap.conf の TLS_CACERT をサーバ側の cn=config で設定している
CA証明書と同じ証明書を指定するようにしたところ、接続に成功しました。

なるほど。サーバ証明書をCA証明書で検証していたわけですね。しかしそもそも、証明書検証が必要なければ省略する方法もあります。※参考→https://wiki.debian.org/LDAP/OpenLDAPSetup#Configuring_LDAPS

/etc/ldap/ldap.conf で TLS_CACERT をコメントアウトし、TLS_REQCERT を never に設定すればいいですね。今回はこちらを採用します。

ということで、irbでもう一度試してみます。

irb(main):001:0> require 'ldap'
=> true

irb(main):002:0> conn = LDAP::SSLConn.new('localhost',LDAP::LDAPS_PORT)
=> #<LDAP::SSLConn:0x0000000166b9e8>

irb(main):003:0> conn.set_option(LDAP::LDAP_OPT_PROTOCOL_VERSION, 3)
=> #<LDAP::SSLConn:0x0000000166b9e8>

irb(main):004:0> conn.bind('cn=admin,dc=test,dc=localhost','admin')
=> #<LDAP::SSLConn:0x0000000166b9e8>

これで接続に成功することを確認できました。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

0 件のコメント:

コメントを投稿