2017年8月21日月曜日

Ruby で net-ldap を使ってユーザの登録、削除、取得をやってみた

概要

前回 Ruby から ldap を操作してみました
グループの追加まで確認できたので今回はユーザ周りの操作を試してみました

環境

  • CentOS 7.3.1611
  • openldap 2.4.40
  • Ruby 2.3.1p112
  • net-ldap 0.16.0

ユーザを追加する

  • vim user_add.rb
require 'net/ldap'
require 'pp'

PORT = 389
HOST = '192.168.100.5'
BASE = 'dc=example,dc=com'
AUTH = {
  :method => :simple,
  :username => "cn=Manager,#{BASE}",
  :password => 'password'
}

ldap = Net::LDAP.new(
  host: HOST,
  port: PORT,
  base: BASE,
  auth: AUTH
)

raise 'bind failed' unless ldap.bind

dn = "uid=hawk,ou=People,#{BASE}"
attr = {
  :sn => 'hawk',
  :cn => 'snowlog',
  :objectclass => ['posixAccount', 'inetOrgPerson'],
  :displayName => 'hawksnowlog',
  :uid => 'hawk',
  :uidNumber => '1001',
  :gidNumber => '1000',
  :homeDirectory => '/home/hawk',
  :loginShell => '/bin/bash',
  :userPassword => '{CRYPT}E1N/hpjy8pfc6',
  :mail => 'hawk@hawksnowlog.cf'
}
ldap.add(
  :dn => dn,
  :attributes => attr
)
pp ldap.get_operation_result

前半の接続部分は前回のコードをそのまま使用しています
ユーザを追加するための処理は dn の定義からです

ポイントは objectclass を配列で指定しているところ
そうしないと後に定義した objectclass に上書きされてしまいます
もし inetOrgPerson を後に記載した場合 'uidNumber' not allowed と言われ uid の指定ができません

#<OpenStruct extended_response=nil, code=65, error_message="attribute 'uidNumber' not allowed", matched_dn="", message="Object Class Violation">

では、posixAccount だけ objectclass に指定するとそんなクラスはないと言われます

#<OpenStruct extended_response=nil, code=65, error_message="no structural object class provided", matched_dn="", message="Object Class Violation">

結局 objectclass を配列にして posixAccount と inetOrgPerson を一緒に指定する必要がありました

あとは実行してエラーが表示されなければ OK です

  • bundle exec ruby user_add.rb
#<OpenStruct extended_response=nil, code=0, error_message="", matched_dn="", message="Success">

userPassword の部分は slappasswd コマンドで作成した暗号化済みのパスワードになります

ユーザを削除する

  • vim user_delete.rb
dn = "uid=hawk,ou=People,#{BASE}"
ldap.delete(
  :dn => dn
)
pp ldap.get_operation_result

削除は dn を指定するだけなので簡単です
add のときと同じように結果が返ってくれば OK です

ユーザを取得する

  • vim user_search.rb
users = ldap.search(base: "ou=People,#{BASE}")
pp users

で以下の表に表示されれば OK です

[#<Net::LDAP::Entry:0x000000015a61e8
  @myhash=
   {:dn=>["ou=People,dc=example,dc=com"],
    :objectclass=>["organizationalUnit"],
    :ou=>["People"]}>,
 #<Net::LDAP::Entry:0x000000015a4258
  @myhash=
   {:dn=>["uid=hawk,ou=People,dc=example,dc=com"],
    :sn=>["hawk"],
    :cn=>["snowlog"],
    :objectclass=>["posixAccount", "inetOrgPerson"],
    :displayname=>["hawksnowlog"],
    :uid=>["hawk"],
    :uidnumber=>["1001"],
    :gidnumber=>["1000"],
    :homedirectory=>["/home/hawk"],
    :loginshell=>["/bin/bash"],
    :userpassword=>["{CRYPT}E1N/hpjy8pfc6"],
    :mail=>["hawk@hawksnowlog.cf"]}>]

特定のグループに所属するユーザを取得する

ということをしたいケースはよくあると思います
search の際に filter という機能を使うことで実現できました
自分は gidNumber を指定してその gidNumber を持つユーザを取得する方法で実現しましたが、他にもやり方はいろいろとあると思います

group = "group1"
groups = ldap.search(base: "cn=#{group},ou=Group,#{BASE}")
groups.each { |group|
  gidNumber = group['gidNumber'][0]
  group_name_filter = Net::LDAP::Filter.eq( "gidNumber", "#{gidNumber}" )
  users = ldap.search(base: "ou=People,#{BASE}", filter: group_name_filter, return_result: true)
  pp users
}

ちょっと複雑なように見えますが一旦 group 名から gidNumber を取得して、取得した gidNumber を元に再度 search をかけています
ポイントは取得した groups をループしたときのクラスが Net::BER::BerIdentifiedArray というクラスなのですが配列になっているので、先頭だけを取得して使っています
今回はグループに 1 つの gidNumber しか持たせていないので先頭を無条件で使っていますが、複数の gidNumber を持つグループの場合は少し考慮が必要になります

最後に

Ruby + net-ldap を使って ldap に基本的なユーザ操作をしてみました
特につまるところはなかった感じです
今回作成したユーザは posixAccount として作成してるので Linux などから SSH ログインすることも可能です

0 件のコメント:

コメントを投稿