必需的软件包
在大多数基于软件包的系统上(例如,在基于 RPM 的分发版(distribution)上,如 Red Hat、Mandrake 和 SuSE)安装和配置 OpenLDAP 是一个相对比较简单的过程。第一步先确定将哪些 OpenLDAP 组件(如果有的话)作为初始 Linux 设置的一部分进行安装。
从控制台窗口或命令行,输入:
[root@thor root]# rpm -qa | grep openldap
openldap-devel-2.0.23-4
openldap-2.0.23-4
openldap-servers-2.0.23-4
openldap-clients-2.0.23-4
[root@thor root]#
您应该看到类似上面的输出。注:Red Hat 分发版安装 OpenLDAP 客户机软件,但不安装 openldap-servers 软件包,即使您选择了服务器配置也是如此。要安装 RPM 软件包,在分发版媒质上找到所需文件的位置并输入:
rpm -ivh packagename
配置 OpenLDAP 服务器
安装了必需的软件之后,下一步是要配置服务器。首先,备份原始配置文件以供今后参考( cp /etc/openldap/slapd.conf /etc/openldap/slapd.conf.orig )。现在,在您所喜爱的文本编辑器中打开 /etc/openldap/slapd.conf 文件,花几分钟时间通读注释。除了定义目录数据库类型、suffix、rootdn 和存储目录数据库的位置的几个项外,slapd.conf 中的大多数缺省设置都是适当的。
database ldbm
suffix "dc=syroidmanor,dc=com"
rootdn "cn=root,dc=syroidmanor.com,dc=com"
rootpw {CRYPT}05T/JKDWO0SuI
directory /var/lib/ldap
index objectClass,uid,uidNumber,gidNumber,memberUid eq
index cn,mail,surname,givenname eq,subinitial
保护 rootdn
rootdn 项控制谁可以对目录数据库进行写操作,以及他们要这样做所必须提供的密码。请确保阅读“访问控制”一章结束部分的注释:
# if no access controls are present, the default is:
# Allow read by all
#
# rootdn can always write!
“rootdn can always write!”(rootdn 总是可以写!)的意思正如它所表示的那样。您在 rootdn 项的 cn= 部分填充的任何项都是对数据库有完全读/写访问权的用户。另外,缺省配置文件使用“secret”作为密码,它以明文形式发送。如果只能从装了防火墙与外界隔离的内部网访问您的 LDAP 服务器,并且确信将访问 LDAP 服务器的用户不知道有关信息包嗅探的任何事情,您大概可以以明文形式安全地发送 rootdn 密码(只要确保将密码“secret”稍加修改,使之不易被猜出)。但是,如果您打算存储在目录中的数据只有一点点机密性,则对密码进行散列处理。可以用 slappasswd 实用程序完成它,如下所示:
[root@thor root]# slappasswd -h {crypt}
该程序将要求您输入密码,然后 slappasswd 将给出与所提供的项相对应的 crypt 字符串。将该字符串剪切并粘贴到 slapd.conf,如上一页所示。其它散列选项包含 SSHA(缺省值)、SMD5、MD5 和 SHA。输入 man slappasswd ,以获取更多信息。
测试服务器
现在是测试服务器的好时机了。这里的配置相对比较简单也容易对可能出现的问题进行故障诊断。在 Red Hat Linux 系统上,命令是:
[root@thor root]# service ldap start
接下来,测试您访问目录的能力:
[root@thor root]# ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
如果正确配置了服务器,您应该看到类似于下面的输出(当然,有不同的 dc):
version: 2
#
# filter: (objectclass=*)
# requesting: namingContexts
#
#
dn:
namingContexts: dc=syroidmanor,dc=com
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
如果您得到了错误消息,或输出与上面有很大的不同,则返回并检查配置。要使 LDAP 服务在重新引导时自动启动,输入以下命令:
[root@thor root]# chkconfig ldap on
再提醒一下,上面的命令特定于 Red Hat 分发版。
配置 ACL
配置 LDAP 服务器的最后一步是设置一些基本访问控制。这样做可以确保用户只能访问他们需要访问的项。
在 OpenLDAP 下设置 ACL(访问控制表,Access Control List)的方法有两种:可以将 include 行放在 /etc/openldap/slapd.conf 的顶部,指向一个单独的文件(例如, include /etc/openldap/slapd.access.conf );或者可以将 ACL 直接添加到 slapd.conf。这完全由您选择 — Mandrake 通常使用 include 行;Red Hat 将 ACL 添加到配置文件。
您将在下一页看到一组示例 ACL 以及它们做些什么的说明。
ACL 示例
# Define ACLs -- access control definitions
access to dn=".*,dc=syroidmanor,dc=com" attr=userPassword
by dn="cn=root,dc=syroidmanor,dc=com" write
by self write
by * auth
access to dn=".*,dc=syroidmanor,dc=com" attr=mail
by dn="cn=root,dc=syroidmanor,dc=com" write
by self write
by * read
access to dn=".*,ou=people,dc=syroidmanor,dc=com"
by * read
access to dn=".*,dc=syroidmanor,dc=com"
by self write
by * read
上面的配置仅允许 userPassword 属性的所有者修改项,但仅当所有者提供他或她的优先密码时才允许进行修改。在所有其它情况下,只能出于认证目的来访问该项,而不能查看它。第二个 access to... 项允许用户修改自己的电子邮件地址(attr=mail)。第三个项指定除了 rootdn 外,对于所有人,ou=people,dc=syroidmanor,dc=com 中的任何 DN 都是只读的。这可防止用户更改其用户名、uid、gid 和主目录等。最后,最后一项是包容前面访问控制中未涉及的任何东西的安全的“大杂烩”。例如,它允许用户更改其自己地址簿中的项。
在服务器可以使用新的 ACL 之前,需要重新启动: service ldap restart 。
完成基本配置之后,应该将一些有用的项填充到数据库。
填充数据
进行到这一阶段,您应该大致了解了 LDAP 的内部机制和结构,并且有了一个正在运行的 OpenLDAP 服务器。下一步是将联系人数据填充到您的目录,随后,电子邮件应用程序将使用这些数据来查询电子邮件地址。遗憾的是,这会使事情变得有点儿棘手。
有三种使联系人信息填入目录树的基本方法:从命令行手工输入,通过 LDIF(LDAP 数据库交换文件 (LDAP Database Interchange File) )导入,或者通过使用脚本。棘手的部分是选择有效的方法以及将数据正确地填入数据库而不出差错。好处就是,一旦完成了,您不必再次执行整个过程 — 当然前提是您继续使用支持 LDAP 的应用程序。
手工填充数据库是三种方法中最直接的一种(虽然,正如单词“手工”暗示的那样,它需要的劳动力最多),所以我们先处理这一过程。
手工数据输入
首先,从控制台窗口或命令行,输入下列命令:
[root@thor root]# ldapadd -D "cn=root" -h
server
password: *******
dn: uid=juser,ou=people,dc=syroidmanor,dc=com
uid: juser
cn: Joe User
givenname: Joe
sn: User
mail: juser@syroidmanor.com
objectClass: top
objectClass: mailRecipient
objectClass: person
objectClass: inetOrgPerson
^D
adding new entry uid=juser,ou=people,dc=syroidmanor,dc=com
[root@thor root]#
上面概述的过程使用三个基本的 LDAP 操作:绑定操作、更新操作和隐式取消绑定操作。为了修改目录,您必须以特权用户身份绑定或连接到 LDAP 服务器。所显示的示例使用 cn=root,因为那就是 OpenLDAP 服务器的配置方式。如果您对 slapd.conf 中的 rootdn 项使用了其它名称,则用合适的替换它。
在密码提示后,输入 DN,后跟要与 DN(RDN 项)相关联的数据,后跟包含类型/值对的属性的对象类。过程结束部分的 CTRL-D 会将数据发送给服务器,并隐式取消与服务器的绑定。然后,LDAP 服务器用一条已经成功输入(已显示)数据的消息或错误消息来响应。常见错误是尝试添加类型/值,而不指定正确的对象类、添加已经存在的用户或 RDN 或遗忘了“MUST”项(例如,对象类人员同时需要 givenname 和 sn)等。
另外,在进行手工数据输入时,要知道以下几点:
您必须知道哪个对象类拥有您正在添加的类型/值 RDN 数据的属性。
该过程所需的工作量较大。
很容易错误地输入一个项,这会使目录树中有错误信息。
一般而言,能使您的目录树布局可视化并熟悉配置 LDAP 服务器以使用的模式很重要。
最后一点对于所有数据输入方法都适用,它正是 LDAP 入门一章的目的。熟悉 LDAP 的结构并清楚地知道您正在尝试完成什么对于消除与填充 LDAP 数据库相关联的失败和不可避免的错误大有帮助。
LDIF 方法
将数据插入 LDAP 目录的第二种方法是使用 LDIF 文件。LDIF 文件只是包含想要插入的以特定语法编排的数据的纯文本文档。您已经熟悉了语法:dn: 后跟树中存储项的位置,后跟一个或多个 RDN 项(包含数据的类型/值对),后跟必需的对象类。要创建 LDIF,使用纯文本编辑器,然后输入想要添加到目录中的数据。使用我们的上一个示例:
dn: uid=juser,ou=people,dc=syroidmanor,dc=com
uid: juser
cn: Joe User
givenname: Joe
sn: User
mail: juser@syroidmanor.com
objectClass: top
objectClass: mailRecipient
objectClass: person
objectClass: inetOrgPerson
保存文件(比如,example.ldif),在控制台窗口或命令行上,输入:
[root@thor root]# ldapadd -x -D "cn=root,dc=syroidmanor,dc=com" -W -f sample.ldif
将提示您输入 rootdn 密码,通过认证后,包含在 LDIF 中的数据将被写入 LDAP 数据库。
LDIF 方法的优缺点
LDIF 方法既有优点也有缺点。其优点为:
在将文件导入数据库之前,您可以检查拼写和语法。
可以创建带有许多项的 LDIF 文件,然后用一个操作将它们添加到目录中。
如果导入失败,只要打开 LDIF 文件,查找错误,并尝试重新导入即可。
LDIF 文件是一种开放标准,几乎可以将它们导入到任何目录服务器中。
其缺点为:
该过程仍需要较大的工作量 — 必须输入 LDIF 中的所有项,并遵循正确的语法。
当 LDAP 服务器遇到导入文件中的错误时,它并不总是能方便地处理。虽然您可能会得到一条“syntax error(语法错误)”消息,但它不会告诉您,在一个相当大的 LDIF 文件中,错误在哪里。
归结起来讲,比起从命令行手工输入数据,LDIF 文件有某些明显的优势。但您仍必须遵守正确的语法来将联系人信息输入文件,并将它导入目录中。有没有一个更自动化的方法来填充 LDAP 数据库呢?— 请继续读下去。
脚本方法
可以使用通常用 Perl 或 PHP 编写的脚本,它们的目的是接收您的数据并将它“自动”放到 LDAP 目录中。这种方法有两个问题。首先,也是最重要的,我亲自尝试过的任何脚本都有许多可恶的错误,在某些最坏的情形下,会在导入期间毁坏您的数据或者破坏目录树本身。其次,使用脚本导入数据假设数据已经以某种形式存在。当分别从 /etc/passwd 和 /etc/groups 导入用户密码和组信息时,这当然很好,但您的联系人信息可能不是通常可识别的格式。毕竟,本教程的主要目的是使联系人信息不受专用格式的支配。
如果将联系信息数据导出成纯文本、用逗号分隔的文件,并找到能够将数据导入 LDAP 目录的脚本,会怎么样呢?如果可以找到这种脚本,并且如果它运行得如它所宣称的那样,则您会得到所有的功能。请记住,您的电子邮件客户机对“用逗号分隔的文件”有其自己精确的解释。要在每行结束的地方添加回车吗?导出程序如何处理嵌入字段中的空格?某些人通常窃用 LDAP 导入脚本来将他们的数据从应用程序 A(已经以格式 X 导出)传送到 LDAP 目录。如果他们的应用程序和导出格式与您的相合,则尝试它。不过要确保先备份您的目录数据库,这样,如果导入失败,您就可以返回到“已知的好”状态。