还是从最基本的说起吧,我的计划是,先给出一个最基本的框架,在此基础上,构 建基本的目录应用;然后将重点放在schema的构建和组织上,说明如何定制自己的schema;最后,我准备以LDAP的API结束LDAP目录服务的 讨论。我将会主要关注的对象是,开源社区中的著名项目,OpenLDAP。又因为已经是奔三的人了,各种逆天的课程已经在百般无耻下流地冲着我狞笑了,所 以我可能没有足够的时间把这些琐碎的学习笔记或者所谓的学习OpenLDAP的心路历程贴上来,但是,我会尽量保证每个星期有一篇blog保质保量的准时 出现在dorm blog上;同时因为水平有限,疏漏之处,在所难免,恳请各位兄弟斧正。
1。如果你使用的是Red Hat,那么可以通过RPM包安装;
2。如果你使用的是debian,那么可以通过apt-get安装;
3。如果你使用的是BSD家族的FreeBSD或者OpenBSD,那么我推荐你采用ports方式安装;
4。如果你想尝试最新的版本,最前沿的功能,你可能需要按照传统的./configure && make && make install三步曲方式安装;
服务端工具:slapadd,slapcat,slapindex,slappassword
服务端配置文件:slapd.conf,slapd.access
客户端工具:ldapadd,ldapdelete,ldapmodify,ldapsearch,ldapmodrdn
客户端配置文件:ldap.conf
OpenLDAP系列之二
这一节我们主要关注如何配置基本的LDAP服务以及构建简单的地址簿.
1.OpenLDAP的服务器程序是/usr/local/libexec/slapd,相应的配置文件为 /usr/local/etc/openldap/slapd.conf,这是OpenLDAP最为重要的一个配置文件,它控制着slapd的各个方面. 它和apache服务器的httpd.conf配置文件所起的作用是一样的.slapd.conf的配置选项很多,完整的配置说明请参见man slapd.conf,通常情况下,OpenLDAP安装之后在/usr/local/etc/openldap目录下包含了slapd.conf的一个 配置范例,如果不是需要对OpenLDAP的各个方面进行精确控制,那么里面的选项多数情况下对我们来说就已经足够了.以下是我的配置文件,所用的系统是 FreeBSD 5.3,其他系统与此类似.
#
# See slapd.conf(5) for details on configuration options.
# This file should NOT be world readable.
#
include /usr/local/etc/openldap/schema/core.schema
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/inetorgperson.schema
# Define global ACLs to disable default read access.
pidfile /var/run/openldap/slapd.pid
argsfile /var/run/openldap/slapd.args
#######################################################################
# BDB database definitions
#######################################################################
database bdb
suffix "o=dormforce.net,c=cn"
rootdn "cn=root,o=dormforce.net,c=cn"
# Cleartext passwords, especially for the rootdn, should
# be avoid. See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
rootpw {MD5}cZZpqIYIUsmEXc/SuEslTA==
# The database directory MUST exist prior to running slapd AND
# should only be accessible by the slapd and slap tools.
# Mode 700 recommended.
directory /var/db/openldap-data
# Indices to maintain
index objectClass eq
下面我对这个简单的配置文件进行解释:
首先,以#开头的行都是注释;如果某行的下一行是以空格或者制表键空出前面的几格,并且没有以#注释掉,那么这一行被认为是上一行的延续. slapd.conf文件一般分为三个部分,最前面是global options,其次是backend options,之后是database options;global options指定全局范围的options;backend options指定某种后端数据库的options,比如可以对DB后端数据库和LDBM后端数据库分别指定一些选项;database options对某个具体的数据库指定一些选项.backend options可以覆盖global options,database options可以覆盖backend options;一开始是三个include行,是global options的一部分:
include /usr/local/etc/openldap/schema/core.schema
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/inetorgperson.schema
这三行指定了包含的schema文件,需要知道,schema文件对于LDAP服务器而言至关重要.在LDAP服务器上存储的各种数据都可以看做是某种对 象,而schema文件指定了每个对象的属性,某些属性是必须要有的,有些属性则是可选的.现在,我们只需要知道,在本文件中,我们必需要包含的就是这三 个schema文件.这三个文件限定了我们将要在服务器上存储的数据对象.
pidfile /var/run/openldap/slapd.pid
argsfile /var/run/openldap/slapd.args
这两行指定将slapd的进程ID号保存到/var/run/openldap/slapd.pid文件中,把slapd的参数保存到 /var/run/openldap/slapd.args文件中.我们没有指定访问控制列表ACL,因此,global options到这里结束.默认情况下,slapd服务器进程允许匿名访问,匿名访问的权限被设置为只读.
本配置文件中我们省略了backend options,因为我们只使用到了BDB数据库;接下来,我们看一下BDB数据库的配置选项:
#######################################################################
# BDB database definitions
#######################################################################
database bdb
suffix "o=dormforce.net,c=cn"
rootdn "cn=root,o=dormforce.net,c=cn"
# Cleartext passwords, especially for the rootdn, should
# be avoid. See slappasswd(8) and slapd.conf(5) for details.
# Use of strong authentication encouraged.
rootpw {MD5}cZZpqIYIUsmEXc/SuEslTA==
# The database directory MUST exist prior to running slapd AND
# should only be accessible by the slapd and slap tools.
# Mode 700 recommended.
directory /var/db/openldap-data
# Indices to maintain
index objectClass eq
这里:
database bdb
这一行指定数据库为BDB数据库;
suffix "o=dormforce.net,c=cn"
指定BDB数据库保存目录树中的"o=dormforce.net,c=cn"子树;
rootdn "cn=root,o=dormforce.net,c=cn"
相当于指定了管理此目录子树的root帐号;
rootpw {MD5}cZZpqIYIUsmEXc/SuEslTA==
相当于指定了管理此目录子树的root用户的口令,本例中我使用了MD5进行加密;
directory /var/db/openldap-data
指定了BDB数据库所在的文件系统目录;
index objectClass eq
指定了数据库索引(注:这个我也没弄明白,但是知道它是用来提高数据库访问速度的).
整个slapd.conf配置文件到此结束.下面我对
suffix "o=dormforce.net,c=cn"
这一行做一下解释:
这里的o表示组织名,我们的组织名是dormforce.net,而c表示国家名,中国表示为cn.
关于目录中识别名DN的命名,RFC并没有规定标准的方法,但是通常使用的有三种方法:
(1)传统方式,顶层为国家名,次顶层为组织名,如:
suffix "o=dormforce,c=cn
(2)域名方式,按照DNS命名方式命名,如:
suffix "dc=dormforce,dc=net"
其中,dc意为domain component.
(3)混合方式,以上两种方式的结合体,本例中就是这样命名的:
suffix "o=dormforce.net,c=cn"
2.配置文件修改好之后,用下面的办法启动slapd服务器进程:
首先,修改/etc/rc.conf文件,添加下面三行:
slapd_enable="YES"
slapd_flags='-h "ldapi://%2fvar%2frun%2fopenldap%2fldapi/ ldap://0.0.0.0/"'
slapd_sockets="/var/run/openldap/ldapi"
然后,在控制台下输入如下命令:
/usr/local/etc/rc.d/slapd.sh start
默认情况下,OpenLDAP会附带安装几个客户端工具,因此我们现在就可以用它们来检查slapd是否正常启动了,在控制台下输入:
ldapsearch -x -b '' -s base '(objectclass=*)' namingContexts
如果能看到类似下面的输出,则表明服务器进程已经正常运行了:
# extended LDIF
#
# LDAPv3
# base <> with scope base
# filter: (objectclass=*)
# requesting: namingContexts
#
#
dn:
namingContexts: o=dormforce.net,c=cn
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
3.下面,我们给LDAP目录服务器添加一些数据,首先打开任何一个编辑器输入如下文本:
#THIS LDIF CAN ONLY BE CREATED AND MODIFIED BY ROCKINS
dn: o=dormforce.net,c=cn
o: dormforce.net
objectClass: organization
dn: ou=cert,o=dormforce.net,c=cn
ou: cert
objectClass: organizationalUnit
dn: ou=noc,o=dormforce.net,c=cn
ou: noc
objectClass: organizationalUnit
dn: ou=synx,o=dormforce.net,c=cn
ou: synx
objectClass: organizationalUnit
dn: ou=member,o=dormforce.net,c=cn
ou: member
objectClass: organizationalUnit
dn: cn=ChenYunChuan,ou=member,o=dormforce.net,c=cn
cn: ChenYunChuan
cn: Rockins
sn: 006
carLicense: A006
departmentNumber: 1
displayName: ChenYunChuan
employeeNumber: 006
employeeType: worker
givenName: Chen
homePhone: 028-82851445
mail: ybc2084@163.com
mobile: 123456789
roomNumber: RunXin 1#330
jpegPhoto:< file:///tmp/hero.jpeg
objectClass: organizationalPerson
objectClass: inetOrgPerson
然后,输入如下命令:
cyc# ldapadd -x -D "cn=root,o=dormforce.net,c=cn" -W -f depart.ldif
将会提示输入LDAP管理口令:
Enter LDAP Password:
输入口令之后,如果出现:
adding new entry "o=dormforce.net,c=cn"
adding new entry "ou=cert,o=dormforce.net,c=cn"
adding new entry "ou=noc,o=dormforce.net,c=cn"
adding new entry "ou=synx,o=dormforce.net,c=cn"
adding new entry "ou=member,o=dormforce.net,c=cn"
adding new entry "cn=ChenYunChuan,ou=member,o=dormforce.net,c=cn"
则表明数据添加成功.
本例中,我们先添加了一个组织o=dormforce.net,c=cn;然后添加了四个ou(组织单元)cert,noc,synx,member,这 里的member组织单元是专门用来存放用户数据的;最后在member组织单元中添加了一个用户cn=ChenYunChuan(我的名字).这个用户 有各种各样的属性,如:
homePhone: 028-82851445
mail: ybc2084@163.com
mobile: 123456789
roomNumber: RunXin 1#330
jpegPhoto:< file:///tmp/hero.jpeg
如果你使用的是专门的LDAP客户端工具,你也可以看到保存到LDAP目录中的jpegPhoto.
4.下面,我们就可以通过邮件客户端,比如Outlook Express搜索我们刚刚创建的LDAP目录了,有关Outlook Express访问LDAP目录服务的具体情况,不在本文讨论的范围之内,详情请参见Outlook Express自带的说明文档.
OpenLDAP系列之三
本文由<<OpenLDAP管理员指南>>第八章翻译而来,原文请见
[url]http://www.openldap.org/doc/admin22/schema.html[/url]
因为是翻译初稿,未经详细推敲和验证,因此按照文中实例进行操作时请三思.同时由于少数几个地方理解尚不透彻,语句可能不甚通顺,我将会在全书翻译完成之后进行进一步的修正,敬请期待.另,版权所有,侵权必究.)
8. 方案规范(Schema Specification)
本章描述了如何扩展slapd的方案(schema).本章假设读者已经熟悉了LDAP/X.500信息模型.
在本章的第一节--已发布的方案文件(Distributed Schema Files)一节中详细描述了发布包中已经定义了的可选的方案,以及指明了从哪里可以获得其它的方案定义.在本章的第二节,方案扩展(Extending Schema),详细描绘了如何定义新的方案项目(schema items).
本章将不讨论如何对slapd内置的系统方案进行扩展,因为这需要在源代码级进行修改.系统方案包含了所有可操作的属性类型(attribute type)或者对像类(object class),这些对像类可能要求必需有或者可以有某个可操作的属性(直接或者间接需要,译者注:如果从上一级对像类或者属性类型继承则属于间接需要).
8.1. 已发布的方案文件(Distributed Schema Files)
OpenLDAP的发布版中包含有一整套为方便你使用而预先定义好的方案规范(Schema Specification).每一组定义的集合都放在某一个方案文件中,而这些方案文件是可以包含到你的slapd.conf(5)配置文件中的(使用 include指令).所有这些方案文件通常都安装在/usr/local/etc/openldap/schema目录下.
Table 8.1: Provided Schema Specifications File Description
core.schema OpenLDAP core (required)
cosine.schema Cosine and Internet X.500 (useful)
inetorgperson.schema InetOrgPerson (useful)
misc.schema Assorted (experimental)
nis.schema Network Information Services (FYI)
openldap.schema OpenLDAP Project (experimental)
要使用这些方案文件,你只需要在slapd.conf(5)的全局定义部分包含所需要的文件就可以了.比如像下面这样:
# include schema
include /usr/local/etc/openldap/schema/core.schema
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/inetorgperson.schema
还有一些其它的文件也是可用的.请参考OpenLDAP FAQ ([url]http://www.openldap.org/faq/[/url]).
------------------------------------------------------------------------------------
注意:你不应该修改这些文件中定义的任何方案项目(schema items).
------------------------------------------------------------------------------------
8.2. 方案扩展(Extending Schema)
可以扩展slapd(8)用到的方案以支持额外的语法,匹配规则,属性类型,和对像类.本章详细描述了用户如何通过slapd当前支持的语法和匹配规则来 给自己的应用加入定制的属性类型和对像类,另外也可以扩展slapd来支持额外的语法,匹配规则和系统方案,但是这需要一定的编程知识,因而不在本文的讨 论范围之内.
定义一个新的方案有五个步骤:
1.获取对像OID
2.选择一个名称前缀
3.创建本地方案文件
4.定义需要定制的属性类型(如果需要的话)
5.定义需要定制的对像类
8.2.1. 对像标识符(Object Identifiers)
每个方案元素都是通过一个全局唯一的对像标识符(OID)来进行标识的.OID也被用于标识其它的对像.它们往往会出现在一些通过ASN.1进行描述的协 议中.特别是,它们在简单网络管理协议(SNMP)中有着很重要的应用.因为OID是以层次结构进行组织的,因此你所在的组织可以获得一个OID并且根据 需要在此基础上衍生出所需要的分支.比如,如果你的组织被授予的OID为1.1,那么你可以像下面这样衍生出一些分支树:
Table 8.2: Example OID hierarchy
OID Assignment
1.1 Organization's OID
1.1.1 SNMP Elements
1.1.2 LDAP Elements
1.1.2.1 AttributeTypes
1.1.2.1.1 myAttribute
1.1.2.2 ObjectClasses
1.1.2.2.1 myObjectClass
当然,你可以在你所在组织的OID下面设计符合组织具体要求的层次结构.无论你选择了什么样的层次结构,你都应该对你所指定的OID进行记录.这可能只是 一个简单的文本文件,也可能是某种更为复杂的组织方式,比如OpenLDAP OID Registry ([url]http://www.openldap.org/faq/index.cgi?file=197[/url]).
要了解更多关于对像标识符的信息(以及所列出的相关服务)请参见:
[url]http://www.alvestrand.no/harald/objectid/.[/url]
无论在什么情况下,你都不应该强行占用(hijack)一个OID的名称空间!
要想无偿地得到一个已注册的OID,请在Internet Assigned Numbers Authority (IANA)所维护的Private Enterprise arc下申请一个OID.任何私营企业(组织)都可以请求获得一个该arc下的OID.只需要到IANA的http: //www.iana.org/cgi-bin/enterprise.pl上填写一份表格即可,你的官方OID通常会在几天后发送给你.你的顶层OID 将会是类似于这样的一串数字:1.3.6.1.4.1.X,这里的X指代的是一个未定的整数.
---------------------------------------------------------------------------------
注意:不要让IANA官方页面上的"MIB/SNMP"语句把你迷惑了.通过上述表格获得的OID可以用于任何目的,当然也包括用来确定LDAP的方案元素(schema element).
---------------------------------------------------------------------------------
另外一种代替的办法是,从本国的权威机构(比如,ANSI,BSI)获取的OID名称空间也是有效的.
在试验阶段,你可以使用1.1作为你的顶层OID.因为OID 1.1 arc被认为是已死亡的名称空间.
8.2.2. (名称前缀)Name Prefix
除了给每个方案元素赋予一个唯一的对像标识符之外,你还应该给每个方案元素提供至少一个名称.名称应该具有描述性,同时还要保证不会和其它方案元素发生冲突.特别是,你选用的任何名称都不应该和现有的以及将来要使用到的Standard Track名称发生冲突.
为了减少(但无法消除)发生名称冲突的可能性,习惯的作法是给非Standard Track的名称加一些字母作为前缀,以使更改被局部化在你的组织内部.组织越小,前缀应该越长.
在下面的例子里面,我们选择了一个简短的前缀'my'(为了节省篇幅).像这样简短的前缀只适用于很大的全球化组织.通常情况下,我们推荐类似下面这样的 前缀,'deFirm'(德国的公司)或者'comExample'(和example.com相关联的组织的元素).
8.2.3. 本地方案文件(Local schema file)
objectclass和attributeTypes(译者注:原文如此,疑为笔误,似乎应该是attributetype)配置指令可以用来为目录中 的条目定义方案规则(schema rules).通常的惯例是创建一个文件包含你自己定制的方案项目.我们推荐你在/usr/local/etc/openldap/schema/下创建 一个local.schema文件并且将此文件包含到你的slapd.conf(5)文件中,注意应该把它放在其它include指令之后.
# include schema
include /usr/local/etc/openldap/schema/core.schema
include /usr/local/etc/openldap/schema/cosine.schema
include /usr/local/etc/openldap/schema/inetorgperson.schema
# include local schema
include /usr/local/etc/openldap/schema/local.schema
8.2.4. 属性类型规范(Attribute Type Specification)
attributetype指令被用于定义新的属性类型.该指令使用同样的Attribute Type Description(按照RFC2252的定义),Attribute Type Description被子方案中子项目的attributeTypes属性使用,比如:
attributetype <RFC2252 Attribute Type Description>
这里的Attribute Type Description是通过下面的BNF定义的:
AttributeTypeDescription = "(" whsp
numericoid whsp ; AttributeType identifier
[ "NAME" qdescrs ] ; name used in AttributeType
[ "DESC" qdstring ] ; description
[ "OBSOLETE" whsp ]
[ "SUP" woid ] ; derived from this other
; AttributeType
[ "EQUALITY" woid ; Matching Rule name
[ "ORDERING" woid ; Matching Rule name
[ "SUBSTR" woid ] ; Matching Rule name
[ "SYNTAX" whsp noidlen whsp ] ; Syntax OID
[ "SINGLE-VALUE" whsp ] ; default multi-valued
[ "COLLECTIVE" whsp ] ; default not collective
[ "NO-USER-MODIFICATION" whsp ]; default user modifiable
[ "USAGE" whsp AttributeUsage ]; default userApplications
whsp ")"
AttributeUsage =
"userApplications" /
"directoryOperation" /
"distributedOperation" / ; DSA-shared
"dSAOperation" ; DSA-specific, value depends on server
这里的whsp表示一个空格字符(' '),numericoid是一个全局唯一的点分十进制形式的OID(比如1.1.0),qdescrs是一个或多个名称,woid要么是一个名称,要么是一个OID,其后可选地跟着一个长度修饰符(比如{10}).
例如,core.schema中的name和cn属性类型是像这样定义的:
attributeType ( 2.5.4.41 NAME 'name'
DESC 'name(s) associated with the object'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} )
attributeType ( 2.5.4.3 NAME ( 'cn' 'commonName' )
DESC 'common name(s) assciated with the object'
SUP name )
注意到每一个属性类型都定义了属性的OID,一个简短的名称,和一个简要的描述.每个名称都是OID的一个别名.slapd(8)在返回结果的时候返回列出的第一个名称.
第一个属性,name,其syntax的值为directoryString(采用UTF-8格式编码的Unicode).这里的syntax的值是通过 OID指定的(1.3.6.1.4.1.1466.115.121.1.15等价于directoryString).同时指定了推荐的长度32768. 服务器应该支持这个长度的值,但是也可能会支持更长的值.如果没有在这个地方指定大小限制,服务器(像slapd)将会把这个地方忽略掉,也就是不会强制 加上大小限制.另外,equality和substring的匹配规则是忽略字母大小写.下表列出常用的syntax和匹配规则(OpenLDAP不仅支 持以下列出的所有syntax和匹配规则,它实际上提供的支持比这里列出的要多得多).
Table 8.3: Commonly Used Syntaxes
Name OID Description
boolean 1.3.6.1.4.1.1466.115.121.1.7 boolean value
directoryString 1.3.6.1.4.1.1466.115.121.1.15 Unicode (UTF-8) string
distinguishedName 1.3.6.1.4.1.1466.115.121.1.12 LDAP DN
integer 1.3.6.1.4.1.1466.115.121.1.27 integer
numericString 1.3.6.1.4.1.1466.115.121.1.36 numeric string
OID 1.3.6.1.4.1.1466.115.121.1.38 object identifier
octetString 1.3.6.1.4.1.1466.115.121.1.40 arbitary octets
Table 8.4: Commonly Used Matching Rules
Name Type Description
booleanMatch equality boolean
caseIgnoreMatch equality case insensitive, space insensitive
caseIgnoreOrderingMatch ordering case insensitive, space insensitive
caseIgnoreSubstringsMatch substrings case insensitive, space insensitive
caseExactMatch equality case sensitive, space insensitive
caseExactOrderingMatch ordering case sensitive, space insensitive
caseExactSubstringsMatch substrings case sensitive, space insensitive
distinguishedNameMatch equality distinguished name
integerMatch equality integer
integerOrderingMatch ordering integer
numericStringMatch equality numerical
numericStringOrderingMatch ordering numerical
numericStringSubstringsMatch substrings numerical
octetStringMatch equality octet string
octetStringOrderingStringMatch ordering octet string
octetStringSubstringsStringMatch ordering octet string
objectIdentiferMatch equality object identifier
第二个属性,cn,是name的一个子属性类型,因此它继承了name的syntax,匹配规则,和usage.而commonName则是cn的一个别名.
两个属性都没有对可拥有的值的个数进行限制.两者都可以由用户在具体应用中使用.两个属性都既没有定义obsolete也没有定义collective.
下面的子章节将给出几个范例.
8.2.4.1. myUniqueName
许多组织都为每一个用户提供了一个唯一的名称.尽管我们可以使用displayName(RFC2798),但是实际上这个属性是可以由用户更改的,而不 是由组织进行更改.我们可以简单的从inetorgperson.schema中拷贝displayName的定义,然后将OID,name,和 description替换成我们想要的,比如:
attributetype ( 1.1.2.1.1 NAME 'myUniqueName'
DESC 'unique name with my organization'
EQUALITY caseIgnoreMatch
SUBSTR caseIgnoreSubstringsMatch
SYNTAX 1.3.6.1.4.1.1466.115.121.1.15
SINGLE-VALUE )
然而,如果我们想把这个名称包含在name声明中的话[比如,(name=*Jane*)],那么取而代之的办法是将myUniqueName定义为name的子属性类型,比如,像这样定义:
attributetype ( 1.1.2.1.1 NAME 'myUniqueName'
DESC 'unique name with my organization'
SUP name )
8.2.4.2. myPhoto
许多组织都为每一位用户保存着一张照片.可以定义myPhoto属性来存放照片.当然,你也可以使用jpegPhoto (RFC2798)(或者它的子属性)来存放照片.但是,只有当你的照片是JPEG文件交换格式(File Interchange Format)的时候你才能这样做.另外一种办法是,定义一个syntax为Octet String的属性类型来存放照片,比如:
attributetype ( 1.1.2.1.2 NAME 'myPhoto'
DESC 'a photo (application defined format)'
SYNTAX 1.3.6.1.4.1.1466.115.121.1.40
SINGLE-VALUE )
在这种情况下,syntax没有指定照片的格式.它假设(注意这样的假设可能是不正确的)所有访问这个属性的应用程序都能够正确处理这个值.
如果你想支持多种照片格式,你可以给每种格式定义一个单独的属性类型,每一种格式的前面加上一些类型信息,或者采用ASN.1来描述这个值同时启用binary传输选项.
另一个替代的方法是定义一个属性来存放照片的URL位置,而非照片本身.你可以采用labeledURI (RFC2079)来建立这样一种模型,或者简单地创建该属性类型的子属性类型,比如,像这样进行定义:
attributetype ( 1.1.2.1.3 NAME 'myPhotoURI'
DESC 'URI and optional label referring to a photo'
SUP labeledURI )
8.2.5. 对象类规范(Object Class Specification)
objectclasses(译者注:原文如此,疑为笔误,似乎应该是objectclass)指令用来定义新的对像类型.该指令使用同样的Object Class Description (按照RFC2252中的定义),Object Class Description在子方案的子条目中被objectClasses属性使用,比如:
objectclass <RFC2252 Object Class Description>
这里的Object Class Description通过下面的BNF定义:
ObjectClassDescription = "(" whsp
numericoid whsp ; ObjectClass identifier
[ "NAME" qdescrs ]
[ "DESC" qdstring ]
[ "OBSOLETE" whsp ]
[ "SUP" oids ] ; Superior ObjectClasses
[ ( "ABSTRACT" / "STRUCTURAL" / "AUXILIARY" ) whsp ]
; default structural
[ "MUST" oids ] ; AttributeTypes
[ "MAY" oids ] ; AttributeTypes
whsp ")"
这里的whsp表示一个空格字符(' '),numericoid是一个全局唯一的点分十进制形式的OID(比如1.1.0),qdescrs是一个或多个名称,而oids则要么是一个或多个名称,要么是一个或多个OID.
8.2.5.1. myPhotoObjec
如果要定义一个辅助的对像类以允许我们在前面定义的myPhoto能够赋给任何已存在的条目.可以像下面这样:
objectclass ( 1.1.2.2.1 NAME 'myPhotoObject'
DESC 'mixin myPhoto'
AUXILIARY
MAY myPhoto )
8.2.5.2. myPerson
如果你的组织想要用一个专有的结构化的对像类来实例化用户.你可以从一个已存在的person类继承,比如从inetOrgPerson (RFC2798)对像类继承,然后加上任何你需要的额外属性.
objectclass ( 1.1.2.2.2 NAME 'myPerson'
DESC 'my person'
SUP inetOrgPerson
MUST ( myUniqueName $ givenName )
MAY myPhoto )
这个对像类继承了inetOrgPerson中的所有必需/可选的属性类型,但同时还要求必需有myUniqueName和givenName属性,而myPhoto属性则是可选的.
8.2.6. OID宏定义(OID Macros)
为了使OID的管理和使用变得轻松,slapd(8)支持对像标识符宏定义(Object Identifier macros).指令objectIdentifier用来使一个宏等价于某一个对应的OID.而这个OID可以是从已有的OID宏定义中获得的. objectIdentifier在slapd.conf(5)的语法是这样的:
objectIdentifier <name> { <oid> | <name>[:<suffix>] }
下面描述了如何定义一组OID宏,同时涉及了如何在定义方案元素的时候使用OID宏定义:
objectIdentifier myOID 1.1
objectIdentifier mySNMP myOID:1
objectIdentifier myLDAP myOID:2
objectIdentifier myAttributeType myLDAP:1
objectIdentifier myObjectClass myLDAP:2
attributetype ( myAttributeType:3 NAME 'myPhotoURI'
DESC 'URI and optional label referring to a photo'
SUP labeledURI )
objectclass ( myObjectClass:1 NAME 'myPhotoObject'
DESC 'mixin myPhoto'
AUXILIARY
MAY myPhoto )
本节将主要关注OpenLDAP的API,我在这里用的软件包是python-ldap,这是一个OpenLDAP的C语言接口的包装版本.鉴于python代码良好的可读性,我不会对代码进行详尽的说明.若有任何疑问请参考相关文档.
在前几节中,我们编写了一个ldif文件,depart.ldif,文件内容如下.然后我们通过ldapadd将depart.ldif文件中的条目添加到了目录树中.在本节中我们将要进行的所有操作都是在这个基础上进行的.
# depart.ldif
# THIS LDIF CAN ONLY BE CREATED AND MODIFIED BY ROCKINS
dn: o=dormforce.net,c=cn
o: dormforce.net
objectClass: organization
dn: ou=cert,o=dormforce.net,c=cn
ou: cert
objectClass: organizationalUnit
dn: ou=noc,o=dormforce.net,c=cn
ou: noc
objectClass: organizationalUnit
dn: ou=synx,o=dormforce.net,c=cn
ou: synx
objectClass: organizationalUnit
dn: ou=member,o=dormforce.net,c=cn
ou: member
objectClass: organizationalUnit
dn: cn=ChenYunChuan,ou=member,o=dormforce.net,c=cn
cn: ChenYunChuan
cn: Rockins
sn: 006
carLicense: A006
departmentNumber: 1
displayName: ChenYunChuan
employeeNumber: 006
employeeType: worker
givenName: Chen
homePhone: 028-82851445
mail: ybc2084@163.com
mobile: 123456789
roomNumber: RunXin 1#330
jpegPhoto:< file:///tmp/hero.jpeg
objectClass: organizationalPerson
objectClass: inetOrgPerson
1.绑定到LDAP服务器:
#!/usr/bin/env python
# file: bind.py
import ldap
ld = ldap.initialize("ldap://202.115.22.157:389")
ld.simple_bind_s("","")
print "bind to LDAP SERVER success"
ld.unbind_s()
我把这个脚本命名为bind.py,每一行的含义是:
#!/usr/bin/env python
表示调用python解释器来运行该文件
# file: bind.py
表明该文件名为bind.py
import ldap
导入ldap模块,和java中的import作用大致相同
ld = ldap.initialize("ldap://202.115.22.157:389")
初始化到LDAP服务器的连接,服务器地址是202.115.22.157(我的机器),端口号是389
ld.simple_bind_s("","")
匿名绑定到服务器上
print "bind to LDAP SERVER success"
在屏幕上打印一行以表明成功绑定到LDAP服务器
ld.unbind_s()
解除与LDAP服务器的绑定
2.搜索条目:
#!/usr/bin/env python
# file: search.py
import ldap
ld = ldap.initialize("ldap://202.115.22.157:389")
ld.simple_bind_s("","")
print "bind to LDAP SERVER success"
print ld.search_s("o=dormforce.net, c=cn", ldap.SCOPE_SUBTREE, "ou=synx")
ld.unbind_s()
这里只比上面多了一行:
print ld.search_s("o=dormforce.net, c=cn", ldap.SCOPE_SUBTREE, "ou=synx")
这一行的作用是在o=dormforce.net, c=cn的子树范围内搜索synx组织单元
此脚本的运行结果如下:
bind to LDAP SERVER success
[('ou=synx,o=dormforce.net,c=cn', {'objectClass': ['organizationalUnit'], 'ou': ['synx']})]
返回给我们的是ou=synx,o=dormforce.net,c=cn条目的各种属性,和我们在depart.ldif文件中所写的信息是一致的.
3.添加条目:
#!/usr/bin/env python
# file: add.py
import ldap
import ldap.modlist
ld = ldap.initialize("ldap://202.115.22.157:389")
ld.simple_bind_s("cn=root,o=dormforce.net,c=cn","secret")
print "root bind to LDAP SERVER success"
attrDict = {'objectClass': ['organizationalUnit'], 'ou': ['test']}
addList = ldap.modlist.addModlist(attrDict)
ld.add_s("ou=test,o=dormforce.net, c=cn", addList)
ld.unbind_s()
这里,有几行需要做特别说明:
import ldap.modlist
导入ldap.modlist,用于根据条目的属性来构造属性列表
ld.simple_bind_s("cn=root,o=dormforce.net,c=cn","secret")
在目录中添加条目是一个特权操作,需要管理员权限,因此以cn=root绑定到服务器,口令是secret
attrDict = {'objectClass': ['organizationalUnit'], 'ou': ['test']}
这是条目所拥有的属性及其对应的属性值,表示为字典中嵌套列表的形式,'ou'是字典的键,而['test']是属性ou对应的值
addList = ldap.modlist.addModlist(attrDict)
根据attrDict构造何时的列表addList
ld.add_s("ou=test,o=dormforce.net, c=cn", addList)
将条目ou=test,o=dormforce.net, c=cn添加到LDAP目录中,addList是条目的属性
运行此脚本后我们用ldapsearch进行验证:
cyc@cyc ~/py $ldapsearch "ou=test"
# extended LDIF
#
# LDAPv3
# base <> with scope sub
# filter: ou=test
# requesting: ALL
#
# test, dormforce.net, cn
dn: ou=test,o=dormforce.net,c=cn
objectClass: organizationalUnit
ou: test
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
显然,该条目已经添加到目录中了.
4.修改条目:
#!/usr/bin/env python
# file: modify.py
import ldap
import ldap.modlist
ld = ldap.initialize("ldap://202.115.22.157:389")
ld.simple_bind_s("cn=root,o=dormforce.net,c=cn","secret")
print "root bind to LDAP SERVER success"
oldAttrDict = {'objectClass': ['organizationalUnit'], 'ou': ['test']}
newAttrDict = {'objectClass': ['organizationalUnit'], 'ou': ['test','experiment'],
'description': ['this is just a experiment organizationUnit']}
modList = ldap.modlist.modifyModlist(oldAttrDict,newAttrDict)
ld.modify_s("ou=test,o=dormforce.net, c=cn", modList)
ld.unbind_s()
这里和添加条目唯一的不同是需要把oldAttrDict和newAttrDict同时传给ldap.modlist.modifyModlist()以生成一个修改条目所需的列表,然后调用ld.modify_s()修改即可.
运行此脚本后我们通过ldapsearch验证:
cyc@cyc ~/py $ldapsearch 'ou=experiment'
# extended LDIF
#
# LDAPv3
# base <> with scope sub
# filter: ou=experiment
# requesting: ALL
#
# test, dormforce.net, cn
dn: ou=test,o=dormforce.net,c=cn
objectClass: organizationalUnit
ou: test
ou: experiment
description: this is just a experiment organizationUnit
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
显然,修改操作是成功的.
5.删除条目:
#!/usr/bin/env python
# file: delete.py
import ldap
import ldap.modlist
ld = ldap.initialize("ldap://202.115.22.157:389")
ld.simple_bind_s("cn=root,o=dormforce.net,c=cn","secret")
print "root bind to LDAP SERVER success"
ld.delete_s("ou=test,o=dormforce.net, c=cn")
ld.unbind_s()
这里,唯一需要说明的是ld.delete_s("ou=test,o=dormforce.net, c=cn")将从目录中把ou=test,o=dormforce.net, c=cn删除.就是这么简单.
我们仍然用ldapsearch进行验证:
cyc@cyc ~/py $ldapsearch 'ou=test'
# extended LDIF
#
# LDAPv3
# base <> with scope sub
# filter: ou=test
# requesting: ALL
#
# search result
search: 2
result: 0 Success
# numResponses: 1
显然,ou=test,o=dormforce.net, c=cn以及从目录中删除了.
参考链接:
[url]http://python-ldap.sourceforge.net/[/url]
[url]http://www.python.org[/url]
[url]http://www.openldap.org[/url]
因为本节讨论的内容不太适合放到前面的几篇里面,故而在这里单独列出,本节内容涉及的范围可能比较杂.同时我也不准备就这一节的内容进行深入讨论.如果感兴趣请参阅相关书籍或链接.
1.安全考虑: 为了保证服务器的安全性,一致性和完整性,OpenLDAP提供了许多额外的功能,如TLS,SSL,Kerberos,SASL,TCP wrapper,关于安全考虑请参见<>第九到十一章:[url]http://www.openldap.org/doc/admin22/security.html[/url]
2.备份和同步: 关于OpenLDAP服务器的备份和同步请参见<>第十三和十四章:[url]http://www.openldap.org/doc/admin22/replication.html[/url]
3.中文编码: 如果要在目录中加入UTF支持,在*nix平台下请试用iconv(1),关于iconv(1)命令请参见*nix手册;另外,在Linux Programmer's Manual中有关于iconv(3)函数的说明.
(全文完)