Skip to content

Ruby Ruby/LDAP 教程

LDAP(轻量级目录访问协议,Lightweight Directory Access Protocol)是一种用于访问和维护分布式目录信息服务的协议。Ruby 可以使用 net-ldap 这个 gem(Ruby 包/库)与 LDAP 服务器交互,net-ldap 是一个纯 Ruby 的 LDAP 客户端库。

net-ldap gem 支持常见的 LDAP 操作,如连接、绑定、搜索、添加、修改和删除条目。它旨在与 LDAP 相关的 RFC(请求评论)文档兼容。

在使用 net-ldap 之前,您需要安装它。通常使用 RubyGems 完成:

$ gem install net-ldap

请确保您有一个正在运行的 LDAP 服务器(例如 OpenLDAP、Active Directory 或基于云的 LDAP 服务)用于测试示例。示例将假定使用本地 OpenLDAP 服务器,但连接详细信息可以轻松调整。

连接到 LDAP 服务器涉及创建一个 Net::LDAP 对象,然后绑定到目录。

您可以使用服务器详细信息初始化一个 Net::LDAP 对象:

require 'net/ldap'
ldap = Net::LDAP.new host: '127.0.0.1', # Your LDAP server IP or hostname
port: 389, # Standard LDAP port (636 for LDAPS)
auth: {
method: :simple,
username: "cn=admin,dc=example,dc=com", # Your admin DN
password: "password" # Your admin password
}
  • host:LDAP 服务器的主机名或 IP 地址。
  • port:LDAP 服务的端口号(默认是 389,或用于 LDAPS/SSL 的 636)。
  • auth:一个哈希,指定认证方法和凭据。:simple 是常见的一种。

这会创建一个对象,但不会立即连接或绑定。

绑定用于认证您的会话。如果在初始化期间提供了认证详细信息,net-ldap 在尝试操作时通常会执行隐式绑定。您也可以使用 ldap.bind 显式绑定。

if ldap.bind
# Successfully bound to LDAP server
puts "Authentication successful!"
# ... perform operations ...
else
# Bind failed
puts "Authentication failed!"
puts "LDAP Error Code: #{ldap.get_operation_result.code}"
puts "LDAP Error Message: #{ldap.get_operation_result.message}"
end

检查 ldap.bind 或任何其他操作的结果是一个好习惯。ldap.get_operation_result 提供有关上次操作的详细信息。

#!/usr/bin/env ruby
require 'net/ldap'
ldap_config = {
host: 'localhost', # Or your LDAP server IP/hostname
port: 389,
auth: {
method: :simple,
username: 'cn=admin,dc=example,dc=com', # Replace with your bind DN
password: 'admin_password' # Replace with your password
}
}
ldap = Net::LDAP.new(ldap_config)
if ldap.bind
puts "Successfully connected and bound to the LDAP server."
# Operations like search, add, modify, delete would go here.
else
puts "Connection or bind failed."
puts "Error code: #{ldap.get_operation_result.code}"
puts "Error message: #{ldap.get_operation_result.message}"
end

要添加条目,需要指定其辨别名(DN,Distinguished Name)和属性(attributes)。

dn = "uid=user1,ou=users,dc=example,dc=com"
attributes = {
objectclass: ["top", "person", "inetOrgPerson"],
cn: "User One",
sn: "One",
givenName: "User",
uid: "user1",
mail: "user1@example.com",
userPassword: "new_password"
}
if ldap.add(dn: dn, attributes: attributes)
puts "Entry '#{dn}' added successfully."
else
puts "Failed to add entry '#{dn}'."
puts "Error: #{ldap.get_operation_result.message}"
end

确保 objectclass 属性对于您的 LDAP 模式和您正在创建的条目类型是正确的。

要修改条目,请指定 DN 和一个操作数组(添加、删除、替换属性值)。

dn_to_modify = "uid=user1,ou=users,dc=example,dc=com"
operations = [
[:replace, :mail, "user.one@example.com"], # Replace existing mail
[:add, :telephoneNumber, "+1234567890"] # Add new attribute
]
if ldap.modify(dn: dn_to_modify, operations: operations)
puts "Entry '#{dn_to_modify}' modified successfully."
else
puts "Failed to modify entry '#{dn_to_modify}'."
puts "Error: #{ldap.get_operation_result.message}"
end

要删除条目,请提供其 DN。

dn_to_delete = "uid=user1,ou=users,dc=example,dc=com"
if ldap.delete(dn: dn_to_delete)
puts "Entry '#{dn_to_delete}' deleted successfully."
else
puts "Failed to delete entry '#{dn_to_delete}'."
puts "Error: #{ldap.get_operation_result.message}"
end

修改条目的相对辨别名(RDN,Relative Distinguished Name)是使用 ldap.rename 完成的。此操作可能不受所有 LDAP 服务器支持,或者可能有限制。

old_dn = "uid=user1,ou=users,dc=example,dc=com"
new_rdn = "uid=newuser1"
# Optional: new_superior_dn = "ou=new_users,dc=example,dc=com"
# delete_old_rdn defaults to true
if ldap.rename(olddn: old_dn, newrdn: new_rdn, delete_attributes: true)
# The new DN will be uid=newuser1,ou=users,dc=example,dc=com
puts "Entry RDN modified successfully."
else
puts "Failed to modify RDN."
puts "Error: #{ldap.get_operation_result.message}"
end

搜索需要一个基本 DN(base DN)、作用域(scope)、过滤器(filter),以及可选的要检索的属性。

base_dn = "ou=users,dc=example,dc=com"
filter = Net::LDAP::Filter.eq("objectclass", "person") # Find all persons
# More complex filter: Net::LDAP::Filter.pres("mail") & Net::LDAP::Filter.eq("sn", "Doe")
attributes_to_fetch = ["cn", "sn", "mail", "uid"]
ldap.search(base: base_dn, filter: filter, attributes: attributes_to_fetch, return_result: false) do |entry|
puts "DN: #{entry.dn}"
entry.each do |attribute, values|
puts " #{attribute}: #{values.join(', ')}"
end
end
# Check for search errors after the block or if return_result: true
result = ldap.get_operation_result
if result.code != 0
puts "Search failed: #{result.message}"
end
  • base:开始搜索的 DN。
  • filter:LDAP 过滤器字符串或 Net::LDAP::Filter 对象。例如,"(uid=user1)" 或 Net::LDAP::Filter.eq("uid", "user1")。
  • attributes:要返回的属性名称数组。如果为空或 nil,通常返回所有用户属性。
  • scope:可以是 Net::LDAP::SearchScope_BaseObject(基对象)、Net::LDAP::SearchScope_SingleLevel(单层)或 Net::LDAP::SearchScope_WholeSubtree(整个子树,默认)。
  • return_result: false(块的默认值)在块中处理条目。如果为 true,ldap.search 将返回一个条目数组。

net-ldap 方法通常在成功时返回 true,在失败时返回 false/nil。操作后,ldap.get_operation_result 提供一个 Net::LDAP::Result 对象,其中包含操作的代码、消息和匹配的 DN。

一个常见的错误检查模式:

if ldap.some_operation(...)
# Success
else
op_result = ldap.get_operation_result
puts "Operation failed!"
puts "Code: #{op_result.code}"
puts "Message: #{op_result.message}"
# op_result.error_message and op_result.matched_dn might also be useful
end

对于一些关键问题,可能会抛出 Net::LDAP::Error 异常,因此也可以使用 begin...rescue Net::LDAP::Error => e 进行更广泛的错误处理。

有关 net-ldap 及其功能的全面详细信息,请参阅: