日常生活中,或者开发过程中,需要管理的目录有很多。 如:人员组织管理,电话簿,地址簿,字典表等。
提供管理和查询目录信息的服务就是目录服务。
有很多厂商实现了目录服务,但是对外提供的接口不统一,所以客户接入一个厂商之后想要切换厂商,成本很高。
所以出现了ldap 协议
ldap 协议规定所有的厂商对外提供接口的时候必须遵守统一的格式,
客户端访问也遵循统一的格式,这样 之后,客户端想要切换厂商只要 改一个地址就可以了。
特点
为什么要用LDAP目录树来存储数据,用MySQL不行吗,为什么非要搞出一个树形的数据库呢?
在LDAP中目录是按照树型结构组织——目录信息树(DIT)
DIT是一个主要进行读操作的数据库 DIT由条目(Entry)组成,条目相当于关系数据库中表的记录;
条目是具有分辨名DN(DistinguishedName)的属性-值对(Attribute-value,简称AV)的集合.
LDIF是LDAP数据库信息的一种文本格式。
LDAP(轻量级目录访问协议,Lightweight Directory Access Protocol)是实现提供被称为目录服务的信息服务。目录服务是一种特殊的数据库系统,其专门针对读取,浏览和搜索操作进行了特定的优化。目录一般用来包含描述性的,基于属性的信息并支持精细复杂的过滤能力。目录一般不支持通用数据库针对大量更新操作操作需要的复杂的事务管理或回卷策略。而目录服务的更新则一般都非常简单。这种目录可以存储包括个人信息、web链结、jpeg图像等各种信息。为了访问存储在目录中的信息,就需要使用运行在TCP/IP 之上的访问协议—LDAP。
LDAP目录中的信息是是按照树型结构组织,具体信息存储在条目(entry)的数据结构中。条目相当于关系数据库中表的记录;条目是具有区别名DN (Distinguished Name)的属性(Attribute),DN是用来引用条目的,DN相当于关系数据库表中的关键字(Primary Key)。属性由类型(Type)和一个或多个值(Values)组成,相当于关系数据库中的字段(Field)由字段名和数据类型组成,只是为了方便检索的需要,LDAP中的Type可以有多个Value,而不是关系数据库中为降低数据的冗余性要求实现的各个域必须是不相关的。LDAP中条目的组织一般按照地理位置和组织关系进行组织,非常的直观。LDAP把数据存放在文件中,为提高效率可以使用基于索引的文件数据库,而不是关系数据库。类型的一个例子就是mail,其值将是一个电子邮件地址。
LDAP的信息是以树型结构存储的,在树根一般定义国家(c=CN)或域名(dc=com),在其下则往往定义一个或多个组织 (organization)(o=Acme)或组织单元(organizational units) (ou=People)。一个组织单元可能包含诸如所有雇员、大楼内的所有打印机等信息。此外,LDAP支持对条目能够和必须支持哪些属性进行控制,这是有一个特殊的称为对象类别(objectClass)的属性来实现的。该属性的值决定了该条目必须遵循的一些规则,其规定了该条目能够及至少应该包含哪些属性。例如:inetorgPerson对象类需要支持sn(surname)和cn(common name)属性,但也可以包含可选的如邮件,电话号码等属性。
o– organization(组织-公司)可以 3~64 个字符长度。
ou – organization unit(组织单元-部门) 最多可以有四级,每级最长 32 个字符,可以为中文。
c - countryName(国家)
dc - domainComponent(域名)dc=xxxx,dc=com
sn – suer name(真实名称)
cn - common name(常用名称)最长可以到 80 个字符,可以为中文。
dn 类似于 Linux 文件系统的绝对路径,每个对象都有一个唯一的名称。
LDAP 目录树的最顶部就是根,也就是所谓的 " 基准DN "。
基准 DN 通常使用三种格式之一
设计目录结构是LDAP最重要的方面之一。下面我们将通过一个简单的例子来说明如何设计合理的目录结构。该例子将通过Netscape地址薄来访文。假设有一个位于美国US(c=US)而且跨越多个州的名为Acme(o=Acme)的公司。Acme希望为所有的雇员实现一个小型的地址薄服务器。
我们从一个简单的组织DN开始:
dn: o=Acme, c=US
Acme所有的组织分类和属性将存储在该DN之下,这个DN在该存储在该服务器的目录是唯一的。Acme希望将其雇员的信息分为两类:管理者(ou= Managers)和普通雇员(ou=Employees),这种分类产生的相对区别名(RDN,relative distinguished names。表示相对于顶点DN)就shi :
dn: ou=Managers, o=Acme, c=US
dn: ou=Employees, o=Acme, c=US
在下面我们将会看到分层结构的组成:顶点是US的Acme,下面是管理者组织单元和雇员组织单元。因此包括Managers和Employees的DN组成为:
dn: cn=Jason H. Smith, ou=Managers, o=Acme, c=US
dn: cn=Ray D. Jones, ou=Employees, o=Acme, c=US
dn: cn=Eric S. Woods, ou=Employees, o=Acme, c=US
为了引用Jason H. Smith的通用名(common name )条目,LDAP将采用cn=Jason H. Smith的RDN。然后将前面的父条目结合在一起就形成如下的树型结构:
cn=Jason H. Smith
+ ou=Managers
+ o=Acme
+ c=US
-> dn: cn=Jason H. Smith,ou=Managers,o=Acme,c=US
现在已经定义好了目录结构,下一步就需要导入目录信息数据。目录信息数据将被存放在LDIF文件中,其是导入目录信息数据的默认存放文件。用户可以方便的编写Perl脚本来从例如/etc/passwd、NIS等系统文件中自动创建LDIF文件。
下面的实例保存目录信息数据为testdate.ldif文件,该文件的格式说明将可以在man ldif中得到。
在添加任何组织单元以前,必须首先定义Acme DN:
dn: o=Acme, c=US
objectClass: organization
这里o属性是必须的
o: Acme
下面是管理组单元的DN,在添加任何管理者信息以前,必须先定义该条目。
dn: ou=Managers, o=Acme, c=US
objectClass: organizationalUnit
这里ou属性是必须的。
ou: Managers
第一个管理者DN:
dn: cn=Jason H. Smith, ou=Managers, o=Acme, c=US
objectClass: inetOrgPerson
cn和sn都是必须的属性:
cn: Jason H. Smith
sn: Smith
但是还可以定义一些可选的属性:
telephoneNumber: 111-222-9999
mail: [email protected]
localityName:Houston
可以定义另外一个组织单元:
dn: ou=Employees, o=Acme, c=US
objectClass: organizationalUnit
ou: Employees
并添加雇员信息如下:
dn: cn=Ray D. Jones, ou=Employees, o=Acme, c=US
objectClass: inetOrgPerson
cn: Ray D. Jones
sn: Jones
telephoneNumber: 444-555-6767
mail: [email protected]
localityName:Houston
dn: cn=Eric S. Woods, ou=Employees, o=Acme, c=US
objectClass: inetOrgPerson
cn: Eric S. Woods
sn: Woods
telephoneNumber: 444-555-6768
mail: [email protected]
localityName:Houston
Schema是LDAP的一个重要组成部分,类似于数据库的模式定义,LDAP的Schema定义了LDAP目录所应遵循的结构和规则,比如一个 objectclass会有哪些属性,这些属性又是什么结构等等,schema给LDAP服务器提供了LDAP目录中类别,属性等信息的识别方式,让这些可以被LDAP服务器识别。
在LDAP的schema中,有四个重要的元素:
1、Objectclass
objectclass定义了一个类别,这个类别会被不同的目录(在LDAP中就是一个Entry)用到,它说明了该目录应该有哪些属性,哪些属性是必须的,哪些又是可选的。一个objectclass的定义包括名称(NAME),说明(DESC),类型(STRUCTURAL或AUXILARY ,表示是结构型的还是辅助型的),必须属性(MUST),可选属性(MAY)等信息。
例如:
这里kunmailUser这种数据,要包含maildir $home $clearpw $forwardAddr $quota $storeHost $delivery $mailReplyText $active等可选项,还要包括username $cn $vuid $vgid 必选项。 可选项用MAY()来包含,必选项用MUST()来包含。DESC是说明项。SUP表示父类(有点像面向对象编程啊)top表示没有父类,他自己是顶级。STRUCTURAL是存储方式。一般来说每个节点都要包含一个ABSTRACT类("top" or "alias"), 至少一个STRUCTURAL类,0个或者多个AUXILIARY类。AUXILIARY表示辅助型、STRUCTURAL表示结构型(默认)、ABSTRACT表示摘要型。
下面定义一个允许将myPhoto增加到任何已经存在的条目中的auxiliary对象类:
如果您的组织需要一个私有的结构化对象类来表示用户,你可以子类化任何一个已经存在的person类,比如inetOrgPerson(RFC2798),然后增加需要的属性:
该对象类从inetOrgPerson中继承允许的或者必须的属性,但是,要求myUniqueName和givenName,允许myPhoto。
2、Attribute
attribute就是一个上面objectclass中可能包含的属性,对其的定义包括名称,数据类型,单值还是多值以及匹配规则等。后面用具体的例子来说明。
Attribute格式:
whsp是空格的意思(' ')。numericoid 是全局唯一的 OID,是带.的十进制形式 (e.g. 1.1.0), qdescrs有一个或几个意思, woid 可以使名称或者是 OID 可选择的一定长度的后缀(e.g {10})。
例如,属性类型name和cn在core.schema中如下定义:
请注意,每一个都定义了属性的OID,给出了一个短的名称,以及一个简短的描述。每一个名称都是OID的一个别名。Slapd(8)在返回结果的时候,将返回第1个列出的名称。
第1个名称,name,保存了directoryString(UTF-8编码的Unicode)语法。该语法由OID说明。(1.3.6.1.4.1.1466.115.121.1.15标识了目录字符串语法)。还说明了一个推荐长度为32768的选项。服务器应该支持该长度的值,但是,也可以支持更长的值。该域没有指明长度限制,因此,在服务器上被忽略,并且服务器不会限制其大小。另外,相等和子串匹配使用不区分大小写的规则。下面是经常使用的语法和匹配规则(OpenLDAP支持这些,以及更多)
第2个属性,cn,是name的一个子类型,因此,它继承了语法,匹配规则,并且使用name.commonName作为别名。
两个属性都没有限制到单一值。都可以被用户应用程序所使用,都不存在过期,都不是集合。
很多组织为用户保留唯一的名字(unique name),虽然用户可以使用displayName,但是这个属性(name)依旧由用户控制。而不是organization。我们可以从 inetorgperson.schema 拷贝displayName ,替换OID,name,和描述(description)。
但是,如果我们要使name属性包含一个断言,这个属性可以被定义为name的子属性。
很多的组织为每一个用户保留一个头像。myPhoto属性类型的定义可以用来保存用户的头像。当然用户可以选择jpegPhoto属性类型(RFC2798)(或其子类型)来保存头像。当然你只能在图片符合JPEG File Interchange Format时使用。
当然,一个使用八进制语法的属性类型可以这样的定义:
在这,语法中并没有置顶photo的格式(format),这里假设访问属性的应用可以对其值进行处理。
如果你想支持多种图片格式,你需要为每一个格式定义属性类型。为图片添加类型信息的前缀。或者使用ASN.1描述值,和use the ;binary transfer option。
可以使图片属性能够保存URI,你可以在labeledURI(RFC2079)后创建一个属性,或者创建一个子类型。
3、Syntax
syntax是LDAP中的“语法”,其实就是LDAP中会用到的数据类型和数据约束,这个语法是遵从X.500中数据约束的定义的。其定义需要有一个ID(遵从X.500)以及说明(DESP)
4、Matching Rules
是用来指定某属性的匹配规则,实际上就是定义一个特殊的Syntax的别名,让LDAP服务器可以识别,并对定义的属性进行匹配。
LDAP的schema的主要元素就是这些了,下面列举出了一些LDAP规定好的或是现在比较通用的schema,一般的LDAP服务器都应该可以识别这些定义。
这就是一个名为subschema的objectclass的定义:
首先是ID,这里是2.5.20.1,接着是NAME,AUXILIARY说明是辅助型,之后是可选属性的定义,subschema中没有定义必须属性,如果需要定义,应该和MAY一样,将属性放在MUST()中并用$隔开
再来看一个属性定义:
可以看到cn属性的父属性是name,它相等性匹配于caseIgnoreMatch(匹配原则为EQUALITY,还有如SUBSTR是字符串匹配,ORDERING是顺序匹配)
syntax定义一般都比较简单,如:
这个定义说明,这一串数字1.3.6.1.4.1.1466.115.121.1.5就代表了LDAP中的字符串,这个数字串的定义和X.500相关,包括了它的存储方式,所占空间大小等。
最后看看Matching Rule的例子,前面提到了caseIgnoreMatch,就看他的吧
其实1.3.6.1.4.1.1466.115.121.1.15 就是LDAP数据类型Directory String的ID,说明前面的cn需要等于这个数据类型才有效。
还有很多常用schema的定义都在了RFC2252中,LDAP服务器都应该支持这些基本的schema。
支持四类10种操作:
查询类 : 搜索 ,比较
更新类: 添加 修改条目,修改条目名, 删除
认证类: 绑定,解绑定
其他类:放弃 ,扩展。
厂商 |
产品 |
介绍 |
SUN |
SUNONE Directory Server |
基于文本数据库的存储,速度快 。 |
IBM |
IBM Directory Server |
基于DB2 的的数据库,速度一般。 |
Novell |
Novell Directory Server |
基于文本数据库的存储,速度快, 不常用到。 |
Microsoft |
Microsoft Active Directory |
基于WINDOWS系统用户,对大数据量处理速度一般,但维护容易,生态圈大,管理相对简单。 |
Opensource |
Opensource |
OpenLDAP 开源的项目,速度很快,但是非主 流应用。 |
OpenLDAP 目录服务有以下10 个优点。
OpenLDAP 是一个跨平台的标准互联网协议,它基于X.500 标准协议。
OpenLDAP 提供静态数据查询搜索,不需要像在关系数据中那样通过SQL 语句维护数据库信息。
OpenLDAP 基于推和拉的机制实现节点间数据同步,简称复制(replication)并提供基于TLS、SASL 的安全认证机制,实现数据加密传输以及Kerberos 密码验证功能。
OpenLDAP 可以基于第三方开源软件实现负载(LVS、HAProxy)及高可用性解决方案,24 小时提供验证服务,如Headbeat、Corosync、Keepalived 等。
OpenLDAP 数据元素使用简单的文本字符串(简称LDIF 文件)而非一些特殊字符,便于维护管理目录树条目, 章
OpenLDAP 可以实现用户的集中认证管理,所有关于账号的变更,只须在OpenLDAP 服务器端直接操作,无须到每台客户端进行操作,影响范围为全局。
OpenLDAP 默认使用协议简单如支持TCP/ZP 协议传输条目数据,通过使用查找操作实现对目录树条目信息的读写操作,同样可以通过加密的方式进行获取目录树条目信息。
OpenLDAP 产品应用于各大应用平台(Nginx、HTTP、vsftpd、Samba、SVN、Postfix、OpenStack、Hadoop 等)、服务器(HP、IBM、Dell 等)以及存储(EMC、NetApp 等)控制台,负责管理账号验证功能,实现账号统一管理。
OpenLDAP 实现具有费用低、配置简单、功能强大、管理容易及开源的特点。
OpenLDAP 通过ACL(Access Control List)灵活控制用户访问数据的权限,从而保证数据的安全性。
在LDAP 的功能模型中定义了一系列利用LDAP 协议的操作,主要包含以下4 部分。
查询操作(ldapsearch):允许查询目录并取得条目,其查询性能比关系数据库好。
更新操作(ldapupdate):目录树条目支持条目的添加、删除、修改等操作。
同步操作:OpenLDAP 是一种典型的分布式结构,提供复制同步,可将主服务器上的数据通过推或拉的机制实现在从服务器上更新,完成数据的同步,从而避免OpenLDAP 服务器出现单点故障,影响用户验证。
认证和管理操作:允许客户端在目录中识别自己,并且能够控制一个会话的性质。
环境:基于centos7,OpenLDAP使用2.4.44版本
使用命令安装OpenLDAP:
yum -y install openldap compat-openldap openldap-clients openldap-servers openldap-servers-sql openldap-devel migrationtools
查看OpenLDAP版本,使用如下命令:
slapd -VV
OpenLDAP2.4.23版本开始所有配置数据都保存在/etc/openldap/slapd.d/
slappasswd -s [password]
密码设置好了之后呢,保存好,下面会使用到。
修改olcDatabase={2}hdb.ldif文件,对于该文件增加一行
olcRootPW: {SSHA}dXgO/Ipy5SQiKFZ0u7m79Xo7uzKIr038,然后修改域信息:
olcSuffix: dc=teracloud2,dc=cn
olcRootDN: cn=admin,dc=teracloud2,dc=cn
注意:其中cn=admin中的admin表示OpenLDAP管理员的用户名,dc为ldap的服务器域名,导出而olcRootPW表示OpenLDAP管理员的密码。
实际修改如下:
vim /etc/openldap/slapd.d/cn=config/olcDatabase\=\{2\}hdb.ldif
olcSuffix: dc=teracloud2,dc=cn
olcRootDN: cn=admin,dc=teracloud2,dc=cn
olcRootPW: {SSHA}dXgO/Ipy5SQiKFZ0u7m79Xo7uzKIr038
修改olcDatabase={1}monitor.ldif文件,如下:
vim /etc/openldap/slapd.d/cn=config/olcDatabase\=\{1\}monitor.ldif
olcAccess: {0}to * by dn.base=”gidNumber=0+uidNumber=0,cn=peercred,cn=extern
al,cn=auth” read by dn.base=”cn=admin,dc=teracloud2,dc=cn” read by * none
验证OpenLDAP的基本配置是否正确,使用如下命令:
slaptest -u
通过结果看出我们的配置是没有问题的
//开始ldap
systemctl enable slapd
//启动ldap
systemctl start slapd
//查看ldap的状态
systemctl status slapd
OpenLDAP默认使用的数据库是BerkeleyDB,现在来开始配置OpenLDAP数据库,使用如下命令:
cp /usr/share/openldap-servers/DB_CONFIG.example /var/lib/ldap/DB_CONFIG
chown ldap:ldap -R /var/lib/ldap
chmod 700 -R /var/lib/ldap
ll /var/lib/ldap/
注意:/var/lib/ldap/就是BerkeleyDB数据库默认存储的路径。
导入基本Schema,使用如下命令:
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/cosine.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/nis.ldif
ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/openldap/schema/inetorgperson.ldif
注意:如果这一步导入失败,一般都是密码输入错误,密码要输上面配置的加密前的密码
dn: dc=teracloud2,dc=cn
objectClass: top
objectClass: dcObject
objectclass: organization
o: Example Inc.
dc: teracloud2
dn: ou=Users,dc=teracloud2,dc=cn
objectClass: organizationalUnit
ou: Users
dn: ou=group,dc=teracloud2,dc=cn
objectClass: organizationalUnit
ou: group
dn: cn=admin,dc=teracloud2,dc=cn
objectClass: organizationalRole
cn: admin
description: Directory Administrator
ldapadd -x -D cn=admin,dc=teracloud2,dc=cn-W -f basedomain.ldif
[root@VM_0_15_centos myself]# ldapadd -x -D cn=admin,dc=teracloud2,dc=cn-W -f basedomain.ldif
Enter LDAP Password:
adding new entry “dc=teracloud2,dc=cn”
adding new entry “ou=people,dc=teracloud2,dc=cn”
adding new entry “ou=group,dc=teracloud2,dc=cn”
adding new entry “cn=admin,dc=teracloud2,dc=cn”
[root@VM_0_15_centos myself]# vim log.ldif
[root@VM_0_15_centos myself]# cat log.ldif
dn: cn=config
changetype: modify
add: olcLogLevel
olcLogLevel: 32
"log.ldif" [New] 4L, 66C written
[root@VM_0_15_centos myself]# ldapmodify -Y EXTERNAL -H ldapi:/// -f log.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "cn=config"
[root@VM_0_15_centos myself]# mkdir -p /var/log/slapd
[root@VM_0_15_centos myself]# chown ldap:ldap /var/log/slapd/
[root@VM_0_15_centos myself]# echo "local4.* /var/log/slapd/slapd.log" >> /etc/rsyslog.conf
[root@VM_0_15_centos myself]# systemctl restart rsyslog
[root@VM_0_15_centos myself]# systemctl restart slapd
[root@VM_0_15_centos myself]# tail -n 4 /var/log/slapd/slapd.log
Sep 5 20:43:31 VM_0_15_centos slapd[4520]: => test_filter
Sep 5 20:43:31 VM_0_15_centos slapd[4520]: PRESENT
Sep 5 20:43:31 VM_0_15_centos slapd[4520]: <= test_filter 6
Sep 5 20:43:31 VM_0_15_centos slapd[4523]: slapd starting
图形操作界面有很多种,包括ldapadmin、ldapadmin.exe,当然还有其他的,这个步骤比较简单,就不详细讲解了
查看ldap的状态,发现无法启动
查看日志发现,有个和证书相关的错误
could not use certificate openLDAP server’,
查看下目录发现没有证书的,目录
把证书拷贝过去,启动,问题解决
1 可以把ApacheDirectoryStudio看做是连接数据库服务器的界面化的client,相当于Navicat、WorkBench。新建连接,连接数据库服务器的操作类似。
ApacheDirectoryStudio下载地址
http://download.csdn.net/download/ljheee/10145654
2 可以用JDBC操作MySQL数据库,进行对数据的增删改查。同样,LDAP树形数据库,也可以通过JDBC方式;除此之外,还可以用JNDI的方式(更推荐),因为树形可以看做是目录,树结构的枝杈相当于目录的层级。
JNDI :全称:JAVA NAMING AND Directory interface
解释:java 命名目录访问接口:java 命名服务和目录服务而提供的统一API。
理解:通过命名来访问需要的资源,类似DNS服务,可通过 key-value的形式。
JNDI是JAVA为命名及目录服务访问制定的基础接口标准,用于访问包括DNS,NIS,LDAP,文件系统等任何以树目录形式存在目标对象,并且基本上可保持访问方式的一致(意味着代码共用)。对于不同的目录类型,JNDI通过使用不同的目录驱动,以保证访问方式的一致
LDAP :全称:LIGHTWEIGHT DIRECTORY ACCESS Protocol
解释: 轻量级目录访问协议。是在20世纪90年代早期作为标准目录协议进行开发的。它是目前最流行的目录协议,与厂商、具体平台无关。LDAP用统一的方式定义了如何访问目录服务中的内容,比如增加、修改、删除一个条目
理解:LDAP用统一的方式定义了如何访问目录服务中的内容,比如增加、修改、删除一个条目。
LDAP 是协议,LDAP 服务可以理解为“层次数据库”服务,相比关系型数据库,查询更快。
关系JNDI - LDAP :
JNDI则是Java中用于访问LDAP的API,开发人员使用JNDI完成与LDAP服务器之间的通信,即用JNDI来访问LDAP,而不需要和具体的目录服务产品特性打交道。这样通过LDAP、JNDI两层抽象,使Java程序对目录服务的访问做到了平台无关性。
连接:
Hashtable env = new Hashtable();
String LDAP_URL = "ldap://:389"; // LDAP 访问地址
String adminName = "example\\user"; // 注意用户名的写法:domain\User 或 cn=user
String adminPassword = "userpassword"; // 密码
env.put(Context.INITIAL_CONTEXT_FACTORY,"com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL, LDAP_URL);
env.put(Context.SECURITY_AUTHENTICATION, "simple");
env.put(Context.SECURITY_PRINCIPAL, adminName);
env.put(Context.SECURITY_CREDENTIALS, adminPassword);
try {
dc = new InitialDirContext(env);// 初始化上下文
System.out.println("认证成功");
} catch (javax.naming.AuthenticationException e) {
System.out.println("认证失败");
} catch (Exception e) {
System.out.println("认证出错:" + e);
}
增加记录
String root = "dc=example,dc=com"; // LDAP的根节点的DC
BasicAttributes attrs = new BasicAttributes();
BasicAttribute objclassSet = new BasicAttribute("objectClass");
objclassSet.add("sAMAccountName");
objclassSet.add("employeeID");
objclassSet.add("sAMAccountName");
objclassSet.add("employeeID");
attrs.put(objclassSet);
attrs.put("ou", newUserName);
dc.createSubcontext("ou=" + newUserName + "," + root, attrs);
LDAP 删除记录
try {
dc.destroySubcontext(dn);
} catch (Exception e) {
e.printStackTrace();
System.out.println("Exception in delete():" + e);
}
修改记录
try {
ModificationItem[] mods = new ModificationItem[1];
/* 修改属性 */
// Attribute attr0 = new BasicAttribute("employeeID", "test");
// mods[0] = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, attr0);
/* 删除属性 */
// Attribute attr0 = new BasicAttribute("description", "test");
// mods[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE, attr0);
/* 添加属性 */
Attribute attr0 = new BasicAttribute("employeeID", employeeID);
mods[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE, attr0);
/* 修改 */
dc.modifyAttributes(dn + ",dc=example,dc=com", mods);
return true;
} catch (NamingException e) {
e.printStackTrace();
System.err.println("Error: " + e.getMessage());
return false;
}
重命名
try {
dc.rename(oldDN, newDN);
return true;
} catch (NamingException ne) {
System.err.println("Error: " + ne.getMessage());
return false;
}
查询
// 创建搜索控件
SearchControls searchCtls = new SearchControls();
// 设置搜索范围
searchCtls.setSearchScope(SearchControls.SUBTREE_SCOPE);
// 设置搜索过滤条件
String searchFilter = "sAMAccountName=" + userName;
// 设置搜索域节点
String searchBase = "DC=example,DC=COM";
// 定制返回属性
String returnedAtts[] = { "url", "whenChanged", "employeeID", "name", "userPrincipalName", "physicalDeliveryOfficeName", "departmentNumber", "telephoneNumber", "homePhone", "mobile", "department", "sAMAccountName", "whenChanged", "mail" };
// 不定制属性,返回所有的属性集
// searchCtls.setReturningAttributes(null);
int totalResults = 0;
try {
NamingEnumeration answer = dc.search(searchBase, searchFilter, searchCtls);
while (answer.hasMoreElements()) {
SearchResult sr = (SearchResult) answer.next();
Attributes Attrs = sr.getAttributes();
if (Attrs != null) {
try {
for (NamingEnumeration ne = Attrs.getAll(); ne.hasMore();) {
Attribute Attr = (Attribute) ne.next();
// 读取属性值
for (NamingEnumeration e = Attr.getAll(); e.hasMore(); totalResults++) {
// 接受循环遍历读取的userPrincipalName用户属性
String user = e.next().toString();
}
// 读取属性值
// Enumeration values = Attr.getAll();
// if (values != null) {
// while (values.hasMoreElements()) {
// System.out.println(" 2AttributeValues=" + values.nextElement());
// }
// }
}
} catch (NamingException e) {
System.err.println("Throw Exception : " + e);
}
}
}
} catch (Exception e) {
e.printStackTrace();
System.err.println("Throw Exception : " + e);
}
搜索范围包含
LDAP 关闭
if (dc != null) {
try {
dc.close();
} catch (NamingException e) {
System.out.println("NamingException in close():" + e);
}
}