语音播报
LDAP简介
LDAP(轻量级目录访问协议,Lightweight Directory Access Protocol)是实现提供被称为目录服务的信息服务 。目录服务是一种特殊的数据库系统,其专门针对读取,浏览和搜索操作进行了特定的优化 。目录一般用来包含描述性的,基于属性的信息并支持精细复杂的过滤能力 。目录一般不支持通用数据库针对大量更新操作操作需要的复杂的事务管理或回卷策略。而目录服务的更新则一般都非常简单 。这种目录可以存储包括个人信息、web链结、jpeg图像等各种信息 。为了访问存储在目录中的信息,就需要使用运行在TCP/IP之上的访问协议—LDAP 。
LDAP最大的优势是:可以在任何计算机平台上,用很容易获得的而且数目不断增加的LDAP的客户端程序访问LDAP目录 。而且也很容易定制应用程序为它加上LDAP的支持。LDAP协议是跨平台的和标准的协议, 。LDAP服务器可以是任何一个开发源代码或商用的LDAP目录服务器(或者还可能是具有LDAP界面的关系型数据库),因为可以用同样的协议、客户端连接软件包和查询命令与LDAP服务器进行交互 。大多数的LDAP服务器安装起来很简单,也容易维护和优化。
LDAP服务器可以用“推”或“拉”的方法复制部分或全部数据,例如:可以把数据“推”到远程的办公室,以增加数据的安全性。复制技术是内置在LDAP服务器中的而且很容易配置。如果要在DBMS中使用相同的复制功能,数据库产商就会要你支付额外的费用,而且也很难管理 。
LDAP允许你根据需要使用ACI(一般都称为ACL或者访问控制列表)控制对数据读和写的权限 。例如,设备管理员可以有权改变员工的工作地点和办公室号码,但是不允许改变记录中其它的域 。ACI可以根据谁访问数据 、访问什么数据、数据存在什么地方以及其它对数据进行访问控制 。因为这些都是由LDAP目录服务器完成的,所以不用担心在客户端的应用程序上是否要进行安全检查 。
LDAP对于这样存储这样的信息最为有用,也就是数据需要从不同的地点读取,但是不需要经常更新。例如,这些信息存储在LDAP目录中是十分有效的:
公司员工的电话号码簿和组织结构图
客户的联系信息
计算机管理需要的信息,包括NIS映射 、email假名,等等
软件包的配置信息
公用证书和安全密匙
LDAP目录中的信息是是按照树型结构组织,具体信息存储在条目(entry)的数据结构中 。条目相当于关系数据库中表的记录;条目是具有区别名DN(Distinguished Name)的属性(Attribute),DN是用来引用条目的,DN相当于关系数据库表中的关键字(Primary Key),用来读取单个记录,以及回溯到树的顶部 。属性由类型(Type)和一个或多个值(Values)组成,相当于关系数据库中的字段(Field)由字段名和数据类型组成,只是为了方便检索的需要,LDAP中的Type可以有多个Value,而不是关系数据库中为降低数据的冗余性要求实现的各个域必须是不相关的 。LDAP中条目的组织一般按照地理位置和组织关系进行组织,非常的直观 。
在windows下部署和使用LDAP服务
1 、安装SLAPD服务器
安装文件为openldap-2.2.29-db-4.3.29-openssl-0.9.8a-win32_Setup.exe,安装路径为C:\Program Files\OpenLDAP
Slapd服务器启动文件在C:\Program Files\OpenLDAP\run下,数据文件在C:\Program Files\OpenLDAP\data中 。
安装中注意要选择ldap作为NT service启动,在windows重启后ldap服务启动,在管理工具的本地服务中可找到OpenLdap的服务选项 。
在cmd命令行下,使用netstat –an命令查看389端口是否Listen 。
2 、修改slapd服务器配置文件
服务器配置文件为C:\Program Files\OpenLDAP\slapd.conf,修改为如下:
ucdata-path ./ucdata
include ./schema/core.schema
include ./schema/cosine.schema
include ./schema/misc.schema
include ./schema/inetorgperson.schema
pidfile ./run/slapd.pid
argsfile ./run/slapd.args
database bdb
suffix "dc=<MY-DOMAIN>,dc=<COM>"
rootdn "cn=Manager, dc=<MY-DOMAIN>,dc=<COM>"
rootpw secret
directory ./data
index objectClass eq
注意:
database使用了bdb数据库,以后添加的数据都进入data文件夹的dbd文件中;
suffix表示服务器后缀,可以认为是根节点或“base DN”,该数据库中的所有条目都有同样的DN后缀;
rootdn和rootpw定义了该目录树的Administrator Entry和密码;
使用正确的域名替换<MY-DOMAIN>和<COM> 。本次test中使用“o=Acme, c=US”;
directory 用来指定目录相关数据的存放位置 。此目录最好只能由运行slapd进程的用户所有,推荐权限为700;
index指定slapd索引时用到的attribute,eq指索引时的匹配规则 。主要是用来优化查询的 。常用到的匹配规则有:approx(模糊匹配, approximate)、eq
(精确匹配,equality)、pres(现值匹配,若某记录的此attribute没有值则不
进行匹配,presence)和sub (子串匹配,substring)
启动桌面的Prompt in OpenLDAP directory,进入slapd服务器安装目录的命令行模式,用以下命令测试ldap server:
ldapsearch -x -s base (objectcontent_txt'>该命令表示返回根目录的条目的dn属性,结果如下:
# extended LDIF
#
# LDAPv3
# base <> with scope base
# filter: (objectcontent_txt'># requesting: namingContexts
#
#
dn:
namingContexts: o=Acme,c=US
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1
注意:使用Ldapsearch -?可以看到更多查询可用选项参数 。
3、使用LDIF文件导入数据
SLAPD服务器使用ldapadd命令和LDIF文件在数据库中导入目录信息数据。LDIF 文件是导入目录信息数据的默认存放文件,其格式如下:
dn:dc=<MY-DOMAIN>,dc=<COM>
objectclass:dcObject
objectclass:organization
o:<MY ORGANIZATION>
dc:<MY-DOMAIN>
dn:cn=Manager,dc=<MY-DOMAIN>, dc=<COM>
objectclass:organizationalRole
cn:Manager
本次test创建init.ldif文件,其目录结构树组织图如图1所示,可使用如下命令之一导入数据:
ldapadd –x –D "cn=Managers, o=Acme, c=US " -W -f init.ldif
或
slapadd -f slapd.conf -l init.ldif
执行完成后,可使用以下search命令看到导入的目录数据及其属性:
ldapsearch -x -b o=Acme,c=US -s sub (sn=Smith)
该命令的意思是以“o=Acme,c=US”作为base dn查询base及其所有子树中sn 属性值为Smith的条目,并列出其所有属性,结果如下:
# extended LDIF
#
# LDAPv3
# base <o=Acme,c=US> with scope sub
# filter: (sn=Smith)
# requesting: ALL
#
# Jason H. Smith, Managers, Acme, US
dn: cn=Jason H. Smith,ou=Managers,o=Acme,c=US
objectClass: inetOrgPerson
cn: Jason H. Smith
sn: Smith
telephoneNumber: 111-222-9999
mail: [email protected]
l: Houston
# search result
search: 2
result: 0 Success
# numResponses: 2
# numEntries: 1 cn=Eric S. Woods
cn=Ray D. Jones cn=Janson
H. Smith ou=Employees
O=Acme,c=US
Organization ou=Manager organizationalUnit
inetOrgPerson
图1:init.ldif 描述的目录树组织结构图
4、 使用LDAP API 访问slapd 服务器
特别提示:建议开发工具使用vs 2003以上版本,vc 6.0中的wldap32.lib 和wldap.h 是98版的,对新的API 并不支持,只更新该库和头文件会引起一系列的编译错误 。
使用LDAP C API 需要包含如下头文件windows.h ,stdio.h 和winldap.h 。
常用的LDAP API 函数列表如下:
LDAP *ldap_init( LDAP_CONST char *hostname, int port );
ldap_init() 返回一个联结句柄, 即一个指向LDAP 结构的指针 。为随后的绑定到目录服务器提供参数值 。如果打开操作失败,返回NULL 。
参数:
hostname 需要联接的LDAP 服务器的一个分离空间的主机名列表或者是代表服务器IP 地址的分离的字符串 。有序列表中的主机都处于准备被联接状态,直到其中有一个被成功联接上为止。本例中使用本机作为LDAP 服务器,因此hostname 的值为”127.0.0.1”或”localhost ”
port 含用于联接的TCP 端口号 。缺省的LDAP 端口能够从常量LDAP_PORT 即默认端口389中获得。
ULONG ldap_set_option(LDAP* ld,int option,void* invalue);
该函数用于设置LDAP 结构的一些选项值,如LDAP 版本号(默认为2)等 。成功则返回LDAP_SUCCESS ,失败则返回错误值,其具体意义参考msdn 。
参数:
ld 指向LDAP 结构的指针;
option 选项名称;
invalue 指向选项值的指针。
int ldap_search_s(
LDAP *ld,
char *base,
int scope,
char *filter,
char *attrs[],
int attrsonly,
LDAPMessage **res);
调用ldap_search_s()或ldap_search_st()进行同步查询。进程将保持一致,除了ldap_search_st()函数的额外参数将指定查询的时延 。两个函数都将直接返回查询的结果: LDAP_SUCCESS或者错误代码 。查询到的条目的返回值将保存在res参数里 。当其中的结果当不再被使用时,将通过调用ldap_msgfree()函数进行释放 。
参数:
ld 连接句柄;
base Base dn 条件值;
scope 为LDAP_SCOPE_BASE,LDAP_SCOPE_ONELEVEL,或LDAP_SCOPE_SUBTREE三值之一,表示查询的范围 。
filter 匹配的字符串,在RFC 1558 [3]中有详细的描述。Test中使用了"object或"sn=Smith"
attrs 为NULL时表示返回所有匹配的条目。非空则只返回匹配的条目属性,以NULL 表示数组的结尾 。
attrsonly 布尔值 。如果为0则返回属性类型以及属性值;非0则只返回属性类型 。timeout 当调用ldap_search_st()时,它将指出本地查询的时延值。
res 当同步调用时,该参数将包含函数调用结束时的一个返回值 。
LDAPMesage *ldap_first_entry( LDAP *ld, LDAPMessage *res );
LDAPMesage *ldap_next_entry( LDAP *ld, LDAPMessage *entry );
int ldap_count_entries( LDAP *ld, LDAPMessage *res );
函数ldap_first_entry()和ldap_next_entry()用于处理查询到的条目结果 。ldap_count_entries() 用于计算返回的条目个数。当没有条目存在时ldap_first_entry()和ldap_next_entry()将返回NULL 。当函数在运行过程中出错时也会返回NULL,但此时ld连接句柄中的ld_errno域将记录该错误信息 。
参数:
ld 连接句柄;
res 查询结果,由同步查询进程获得;
char *ldap_first_attribute(
LDAP *ld,
LDAPMessage *entry,
BerElement **ptr);
char *ldap_next_attribute(
LDAP *ld,
LDAPMessage *entry,
BerElement *ptr);
用于得到查询到的条目的属性。当达到最后一个属性时,函数ldap_first_attribute()
和ldap_next_attribute()将返回NULL,此时,ld句柄中的ld_errno 域将被设置为error 。两个进程都将返回一个指向包含当前属性名的连接缓冲的指针。这将被当作静态数据对待 。ldap_first_attribute()将定位并返回一个指向BerElement类型的名为ptr的指针,以保存当前位置的路径 。该指针将被后面的调用ldap_next_attribute() 所引用,以获得下一个条目的属性结果 。
参数:
ld 连接句柄;
entry 需处理的属性结果所在的条目,即ldap_first_entry()或ldap_next_entry()的返回值;
ptr 在函数ldap_first_attribute()中,用于保存当前条目所在位置的地址指针 。函数ldap_next_attribute()所用到的指针为先前调用ldap_first_attribute()获得的返回值 。
char **ldap_get_values(
LDAP *ld,
LDAPMessage *entry,
char *attr);
struct berval **ldap_get_values_len(
LDAP *ld,
LDAPMessage *entry,
char *attr);
int ldap_count_values( char **vals );
int ldap_count_values_len( struct berval **vals );
int ldap_value_free( char **vals );
int ldap_value_free_len( struct berval **vals );
上述函数均为获得属性值的相关函数。ldap_get_values()和ldap_get_values_len()用于获得条目的属性值。ldap_count_values()和ldap_count_values_len()用于计算返回值的个数 。ldap_value_free()和ldap_value_free_len()用于释放返回的属性值。注意,当返回的值不再使用时,应调用函数ldap_value_free()或ldap_value_free_len()进行释放 。
参数:
ld 连接句柄;
entry 属性所属的条目,即ldap_first_entry()或ldap_next_entry()的返回值;
attr 返回值的属性,即ldap_first_attribute()或ldap_next_attribute()或一个字符串调用的返回值(例如,"mail");
vals 先前调用ldap_get_values()或ldap_get_values_len()的返回值 。两种不同形式的调用都是有条件的 。第一重形式只适用于非二进制的字符串类型数据;第二种_len形式适用于任何形式的数据。
PCHAR ldap_get_dn(
LDAP* ld,
LDAPMessage* entry);
待续……
5、调用API查询范例
文件为LdapTest.cpp,注意在附加依赖项下面添加wldap32.lib,需要列出base dn 下符合sn=Smith条目的telephoneNumber和mail属性及其值。运行结果如下: Init succeeded
ldap_set_option succeeded version set to 3
ldap_first_entry succeeded
ENTRY NUMBER 0
ATTR: telephoneNumber: 111-222-9999
ATTR: mail: [email protected]
在Linux下部署和使用安装LDAP
1 、安装SLAPD服务器
在www.openldap.com上下载最新的release ldap package,解压,命令行下进入已解压目录(解压包建议放在root目录下),指定安装目录(如/usr/local),如下所示: [[email protected] openldap-2.4.8]# ./configure
安装即刻开始,最后一行提示如下结果:
Please run "make depend" to build dependencies
使用make depend命令编译依赖选项;
使用make编译OPENLDAP,这个命令编译了LDAP库,以及LDAP客户端,还有slapd和slurpd 。
使用make test执行测试程序测试编译
安装:su root -c 'make install'
在Linux 2.6.18-53.el5(使用uname –r查看)以上,操作系统的安装程序中已经附带了完整的openldap安装包,默认安装目录是/etc/openldap,LDAP服务需要使用的配置文件slapd.conf 和ldap.conf 都在此目录下配置,此目录下DB_CONFIG.example 需要copy至/var/lib/ldap,并更名为DB_CONFIG作为数据库配置文件 。在确认与openldap相关的四个安装包都已经安装,相关配置文件也已经正确配置以后,使用service ldap start启动slapd服务器,显示结果如下时表示服务器已经正常启动,否则请检查相关配置文件的正确性:
停止slapd:[确定]
正在检查slapd 的配置文件:config file testing succeeded
[确定] 启动slapd:[确定]
此处我们使用了与windows基本相同的slapd.conf配置文件,唯一的区别就是密码使用了MD5加密(slappasswd –h {MD5}),注意查询服务器正确运行的命令与windows下略有区别,是:
ldapsearch –x -s base '(object namingContext
显示结果应该如下:
然后使用init.ldif导入新的数据,命令为:
ldapadd -x -D "cn=root,o=Acme,c=US" -W -f /etc/openldap/init.ldif
结果如下:
现在的数据结构组织也如图一所示,可使用ldapsearch -x -b 'o=Acme,c=US' -s sub '(sn=Smith)'获取符合sn=Smith条件的条目信息,结果如下:
2、使用LDAP C API访问slapd服务器
需要包含头文件ldap.h,查看文件可知,有很多函数已经做了更新,如果要继续使用,需要定义LDAP_DEPRECATED为一个非零值,最新的package建议采用更新后的函数 。
新建工程后需要在Automake管理器的项目选项中设置添加工程外的代码库如下图所示:
图2:添加LDAP API库
当前使用的LDAP API版本已经升级了很多函数,但也为以前的函数保留了一个编译
选项,所以在使用之前还需要添加一个编译选项,如图所示:
图3:添加支持旧API的编译选项
然后就可以使用前面用过的LdapTest.cpp 来做一下测试了 。
3、 LDAP的可视化管理工具:phpLDAPadmin
在安装此软件前,需要先安装web服务器apache和PHP,Linux5的系统软件就自
带上述软件的安装包,编辑/var/www/html/phpldapadmin/config/config.php,可直接copy该目录下的config.php.example,再根据需要进行编辑修改 。几个比较关键的参数如下:
$i=0;
$ldapservers = new LDAPServers;
$ldapservers->SetValue($i,'server','name','My LDAP Server');
$ldapservers->SetValue($i,'server','host','127.0.0.1');
$ldapservers->SetValue($i,'server','port','389');
$ldapservers->SetValue($i,'server','base',array('o=Acme, c=US'));
$ldapservers->SetValue($i,'login','dn','cn=root,o=Acme,c=US');
$ldapservers->SetValue($i,'login','pass','secret');
$ldapservers->SetValue($i,'appearance','show_create',true);
$ldapservers->SetValue($i,'login','anon_bind',true);
在完成配置文件修改后,重新启动http服务,然后通过浏览器访问http://localhost/phpldapadmin,显示如下界面
图4:phpLDAPadmin登录界面
图5:成功登录
图6:条目列表
。