分享

java ldap

 java_laq小馆 2013-12-22




1. 从用途上阐述LDAP,它是一个存储静态相关信息的服务,适合“一次记录多次读取”。常用LDAP服务存储的信息:
  • 公司的物理设备信息(如打印机,它的IP地址、存放位置、厂商、购买时间等)
  • 公开的员工信息(地址、电话、电子邮件…)
  • 合同和账号信息(客户信息、产品交付日期、投标信息、项目信息…)
  • 凭证信息(认证凭证、许可证凭证…)


2. 从数据结构上阐述LDAP,它是一个树型结构,能有效明确的描述一个组织结构特性的相关信息。在这个树型结构上的每个节点,我们称之为“条目 (Entry)”,每个条目有自己的唯一可区别的名称(Distinguished Name ,DN)。条目的DN是由条目所在树型结构中的父节点位置(Base DN)和该条目的某个可用来区别身份的属性(称之为RDN如uid , cn)组合而成。对Full DN :“shineuserid=linly , ou=Employee , dc=jsoso , dc=net”而言,其中Base DN:“ou=Employee , dc=jsoso , dc=net”,RDN:“shineuserid=linly”下面是一个LDAP服务器的数据结构图:

3. 从协议衍化上阐述LDAP,它是“目录访问协议DAP——ISO X.500”的衍生,简化了DAP协议,提供了轻量级的基于TCP/IP协议的网络访问,降低了管理维护成本,但保持了强壮且易于扩充的信息框架。 LDAP的应用程序可以很轻松的新增、修改、查询和删除目录内容信息。

LDAP目录条目(Directory Entry)简述
从Object Classes谈起
在 LDAP目录数据库中,所有的条目都必须定义objectClass这个属性。这有点像Java语言里说阐述的“一切皆对象”的理念,每个条目(LDAP Entry)都要定义自己的Object Classes。Object Class可以看作是LDAP Entry的模板,它定义了条目的属性集,包括必有属性(requited attribute)和可选属性(option attribute)。这里要着重指出的是,在LDAP的Entry中是不能像关系数据库的表那样随意添加属性字段的,一个Entry的属性是由它所继承 的所有Object Classes的属性集合决定的,此外可以包括LDAP中规定的“操作属性”(操作属性是一种独立于Object Class而存在的属性,它可以赋给目录中的任意条目)。如果你想添加的属性不在Object Classes定义属性的范畴,也不是LDAP规定的操作属性,那么是不能直接绑定(在LDAP中,给Entry赋予属性的过程称为绑定)到条目上的,你 必须自定义一个含有你需要的属性的Object Class,而后将此类型赋给条目。
Object Class是可以被继承的,这使它看上去真的很像Java语言中的POJO对象。继承类的对象实例也必须实现父
类 规定的必有属性(requited attribute),同时拥有父类规定的可选属性(option attribute)。继承类可以扩展父类的必有属性和可选属性。由于Object Class的继承特性,因此在一个LDAP Entry上,objectClass属性是一个多值属性,它涵盖了Object Class的完整继承树,如用户条目uid=Linly , ou=People, dc=jsoso , dc=net,它直接实现了inetorgperson这个对象类,那么它的objectClass属性值为 inetorgperson,organizationalPerson,person,top。

从Object Classes到Directory Server Schema
上 一章节中,我们了解了LDAP条目都要遵守的一个最重要的规定Object Classes,而实际上,对Entry更多更细的规范被涵盖在了Directory Server Schema(目录服务模式)中。Directory Schema声明了完整的LDAP数据的存储规范,这包括数据的字节大小、数值范围和格式定义。
默 认的,在一个LDAP服务器上,都定义有一套标准的Schema和一套为服务器功能定制的Schema。用户在需要的时候,是可以定制自己的LDAP属性 和Object Class,以扩展标准Schema的功能。在Sun Directory Server中,使用了标准LDAPv3 Schema,并在此基础上做了轻微的扩展。

在Schema中的标准属性(Standard Attributes)是一个键-值对,如:cn:linly ,属性ID(属性名)为cn,属性值为linly 。事实上,一个完整的条目就是由一系列的键-值对组成的。以下是一个完整的LDAP Entry:

引用
dn: uid=Linly,ou=People, dc=jsoso,dc=net
telephoneNumber: 13950491407
mail: linliangyi2005@gmail.com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: inetorgperson
cn: LinLiangyi
userPassword: {SSHA}aPTgP47LeziVGqjPBI8343FwkcL3QgQQ9kirXw==
creatorsName: uid=admin,ou=administrators,ou=topologymanagement,o=netscaperoot
createTimestamp: 20080219070003Z
nsUniqueId: 2deb0d01-deb811dc-8055dc88-5f880db9
nsRoleDN: cn=MyAdminRole,ou=People,dc=jsoso,dc=net
nsRoleDN: cn=secondRole,ou=People,dc=jsoso,dc=net
cn;phonetic;lang-zh:: IA==
preferredLanguage: zh-CN
cn;lang-zh:: 5p6X6Imv55uKICA=
givenName: liangyi
givenName;lang-zh:: 6Imv55uK
sn: lin
sn;lang-zh:: 5p6X
uid: linly
manager: cosTemplateForPostalCode
modifiersName: uid=admin,ou=administrators,ou=topologymanagement,o=netscaperoot
modifyTimestamp: 20080227083015Z



在Schema中,对属性的定义包含以下内容:

  • 一个唯一的属性名称
  • 一个属性的OID(object  identifier)
  • 一段属性的文本描述信息
  • 一个关联属性文法定义的OID
  • 属性的单值/多值描述;属性是否是目录自有的;属性的由来;附加的一些匹配规则



此外Schema中最重要的部分就是我们上面提到的Object Classes,它实际上是预定义的一套捆绑成套的属性集合。在Schema定义中,Object Classes要包含以下内容:

  • 一个唯一的名字
  • 一个object identifier (OID) 定义Object Class
  • 一个必有的属性集合
  • 一个可选的属性集合



高级LDAP条目
在目录服务中,信息是以条目的形式被分层次的组织在一起的。LDAP提供了几种分组机制,使得信息管理更富有弹性。

静态组和动态组(Static Group and Dynamic Group)
组(Group),声明一个目录条目的集合
静态组(Static Group):显式声明了一个它的集合成员,这种方式适用于少量明确的成员组合。
动态组(Dynamic Group):它定义了一个过滤条件,所有匹配条件的条目都是组的成员。所以称之为动态组,是因为每次读取其组员名单时,要动态计算过滤条件。
使用组的优点是能够快速的查找所属的成员;缺点是,给出任意的成员,无法获知它所属的组。因此从数据关联关系上看,Group适合一对多的查询。

受管角色、过滤器角色和嵌套角色(Managed Role、Filtered Role and Nested Role)
角色(Role),它是条目的另一种集合形式。它与组不同的在于,给定一个任意的成员条目,我们能立刻获知它所属的角色。因此从数据关联关系上看,Role适合多对一的查询。角色定义仅对它们的父节点子树下面的目录条目有效。
受管角色(Managed Role),它等价于Group中的静态组,不同的是,Role不是把组员信息添加到自身属性中,而是将自身的DN添加到组员条目的nsroledn属性中。
过滤器角色(Filtered Role),它与动态组相似,通过定义条目过滤器来确定组员。
嵌套角色(Nested Role),它是对角色定义的一种嵌套形式。可以嵌套其他的嵌套角色的。嵌套角色的成员,是其包含的所有角色成员的合集。嵌套角色通过包含从属于其它子树下的角色,可以扩展其搜索的scope。

服务类CoS
服 务类实际上是一种属性的共享机制,它无须定义条目间的关联关系,却可以做到数据同步和空间优化。例如,在一个公司目录下,拥有上千个员工,他们拥有相同的 公司地址属性;在传统的条目中,地址属性分别存贮在员工条目里,这样不但浪费存储空间,一旦地址变更,则要对员工条目进行逐一修改。采用CoS机制后,公 司地址属性被存放在一个对象内,员工条目通过引用这个对象来获得地址信息,从而缩小的存储空间损耗,并方便了信息的修改。
CoS仅对其父节点子树下面的目录条目有效。CoS机制包含两个部分,CoS 定义条目和CoS模板条目。定义条目描述了属性是如何被引用的;模板条目描述了属性的值。CoS机制包含3种类型:
指针服务类(Pointer CoS),
在Pointer CoS中,CoS包含一个定义Definition Entry,它指定了两个属性:1.共享属性的名称;2.提供共享数据的模板DN。 另外CoS还要有一个Template Entry,它要提供共享的数据。
在定义了Definition Entry和Template Entry后,Pointer CoS将为其父节点子树下面的所有条目(目标条目Target Entry)分配共享属性和模板所定义的值。示意图如下:

Definition Entry:cn=PointerCoS , dc=example , dc= com定义了CoS的共享属性cosAttribute:postalCode,同时定义了CoS的模板DN cosTemplateDN:cn=cosTemplateForPostalCode,cn=data。
Template Entry: 它是CoS的模板,定义了共享属性值 postalCode:45773。
Target Entry:它是目标条目,因为它位于dc=example , dc=com的子树下。所以它获得了共享属性postalCode:45773。

间接服务类(Indirect CoS),
在使用间接服务类时,在Definition Entry条目中定义了CoS的共享属性cosAttribut和一个用来间接指向模板的属性cosIndirectSpecifier。
首先,我们需要用cosIndirectSpecifier的值A作为属性名,来检索CoS父节点子树中所有拥有A属性的条目,作为目标条目Target Entry。
其次,根据找到的Target Entry条目中A属性的值来定位模板对象。
最后,再分别根据找到的模板对象中拥有的共享属性值赋给对应的Target Entry。
例如,定义如下Definition Entry

引用
dn: cn=generateDeptNum,ou=People,dc=example,dc=com
objectclass: top
objectclass: LDAPsubentry
objectclass: cosSuperDefinition
objectclass: cosIndirectDefinition
cosIndirectSpecifier: manager
cosAttribute: departmentNumber


该CoS定义对条目ou=People,dc=example,dc=com下的子树中所有具有manager属性的条目有效,同时设定其CoS模板指向manager属性的值所指向的条目。
又假定有如下的Template Entry条目,它具有属性departmentNumber:

引用
dn: cn=Carla Fuentes,ou=People,dc=example,dc=com

objectclass: cosTemplate

departmentNumber: 318842


同时在ou=People,dc=example,dc=com下有Target Entry如下:

引用
dn: cn=Babs Jensen,ou=People,dc=example,dc=com
cn: Babs Jensen
...
manager: cn=Carla Fuentes,ou=People,dc=example,dc=com
departmentNumber: 318842


因为该Entry具有manager属性,且在ou=People,dc=example,dc=com子树下,所以它成为了Target Entity。并且由于其manager的值指向模板cn=Carla Fuentes,ou=People,dc=example,dc=com,因此,它的departmentNumber为 318842。

经典服务类(Classic CoS)
经 典服务类同间接服务类有点相似,它也是对属性的间接应用。在Classic CoS的定义条目中,除了共享属性定义外,还有两个定义,一个是cosTemplateDn,它指向模板条目的父节点;另一个是 cosSpecifier,它的值指向目标条目的属性A。由目标条目的属性A的值来代替模板条目的RND。则目标条目的属性A的值加上 cosTemplateDn的值恰好定义一个唯一的模板条目。
举例如下,首先是一个经典服务类的定义条目:

引用
dn: cn=classicCoS,dc=example,dc=com
objectclass: top
objectclass: LDAPsubentry
objectclass: cosSuperDefinition
objectclass: cosClassicDefinition
cosTemplateDn: ou=People,dc=example,dc=com
cosSpecifier: building
cosAttribute: postalAddress


该定义条目指明了3个参数,
1. 要共享的属性是postalAddress
2. 模板条目的上下文前缀是ou=People,dc=example,dc=com
3. 模板条目的RDN存储于目标条目的building属性中
其次,假定有如下模板条目:

引用
dn: cn=B07,ou=People,dc=example,dc=com
objectclass: top
objectclass: LDAPsubentry
objectclass: extensibleobject
objectclass: cosTemplate
postalAddres: 7 Old Oak Street$Anytown, CA 95054


最后,我们假设有以下目标条目:

引用
dn: cn=Babs Jensen,ou=People,dc=example,dc=com
cn: Babs Jensen
...
building: B07
postalAddres: 7 Old Oak Street$Anytown, CA 95054


由于目标条目中,building属性的值是B07,因此该条目的模板定义DN = B07加上ou=People,dc=example,dc=com ,即cn=B07,ou=People,dc=example,dc=com,因此目标条目的postalAddres 引用模板的值7 Old Oak Street$Anytown, CA 95054。

LDAP 目录搜索
LDAP搜索是目录服务最常用的功能之一。在LDAP服务中搜索要用到相应的Filter语句。Filter语句由3个部分组成:
1. 属性,如:cn ,uid ,操作属性如:objectClass  ,  nsroledn
2. 比较操作符 ,如 < , > ,= ,…
3. 逻辑预算符,如: 与操作&  , 或操作| , 非操作!
关于Filter语句组成的详细参数表如下:
filter的运算符

filter布尔运算符


搜索过滤器示例

  • 下列过滤器将搜索包含一个或多个 manager 属性值的条目。这也称为存在搜索:manager=*
  • 下列过滤器将搜索包含通用名 Ray Kultgen 的条目。这也称为等价搜索:cn=Ray Kultgen
  • 下列过滤器返回所有不包含通用名 Ray Kultgen 的条目:(!(cn=Ray Kultgen))
  • 下列过滤器返回的所有条目中都有包含子字符串 X.500 的说明属性:description=*X.500*
  • 下列过滤器返回所有组织单元为 Marketing 且说明字段中不包含子字符串 X.500 的条目:(&(ou=Marketing)(!(description=*X.500*)))
  • 下列过滤器返回所有组织单元为 Marketing 且 manager 为 Julie Fulmer 或 Cindy Zwaska 的条目:(&(ou=Marketing)(|(manager=cn=Julie Fulmer,ou=Marketing,dc=siroe,dc=com)(manager=cn=Cindy Zwaska,ou=Marketing,dc=siroe,dc=com)))
  • 下列过滤器返回所有不代表人员的条目:(!(objectClass=person))
  • 下列过滤器返回所有不代表人员且通用名近似于 printer3b 的条目:(&(!(objectClass=person))(cn~=printer3b))



ldapsearch指令参数-b 搜索的起始上下文

  • -D 绑定搜索的账号Distinguished Name
  • -h 主机名。地址
  • -p LDAP服务端口
  • -l 搜索的最大耗时
  • -s 从上下文开始的搜索范围,有三个常量base(表示仅当前根对象)/one(当前根对象及下一级)/sub(当前根对象的全部子树)
  • -W 绑定账号密码
  • -z 返回结果的最大数量



搜索“操作属性”
在LDAP搜索中,操作属性在默认情况下是不会跟随搜索结果返回的。必须在搜索中明确显示的指定操作属性,如:

引用
ldapsearch -h linly.jsoso.net -p 5201 -D "cn=directory manager" -w password "objectclass=*" aci=accounts。



搜索“操作对象类”的条目
在LDAP中Role、CoS等对象被定义为特殊的 Object Class——操作对象类(operational object class),在一般的搜索中,这类对象是不会作为结果返回给用户的。要想查找这些对象,必须在filter中显式定义要找这个对象类。例如: (objectclass=ldapsubentry)。

ACI权限控制
ACI(Access Control Instruction)访问控制指令是LDAP 服务中用以控制用户访问权限的有力手段。在目录的Entry中,aci属性记录了对该条目的多条访问控制指令。(aci属性是一个多值操作属性,可以赋予任意的LDAP条目)
ACI的语法格式如下:aci: (target)(version 3.0;acl "name";permission bind_rules;)
target 指定了ACI要控制访问的目标属性(集合)或条目(集合)。target可以用DN,一个或多个属性,或者一个filter来定义。它是一个可选项。
target语法是:关键字 <op> 表达式
target关键字表

(更多详细的target用法,请参阅 Sun ONE Directory Server 5.2 Administration Guide )

version 3.0 这是一个必须的常量字窜,用以识别ACI的版本。

name 指定ACI的名称,可以使任意的字窜,只要区别于同一个条目aci属性下的其他ACI,这是一个必须属性。

permission 指定权限许可。
权限包括:read、write、add、delete、search、compare、selfwrite、 proxy 或 all,其中all表示出了proxy之外的所有操作。
权限语法:allow | deny (权限)

bind_rules 绑定规则。绑定规则定义了何人、何时,以及从何处可以访问目录。绑定规则可以是如下规则之一:

  • 被授予访问权限的用户、组以及角色
  • 实体必须从中绑定的位置
  • 绑定必须发生的时间或日期
  • 绑定期间必须使用的验证类型


绑定规则语法:keyword  = 或者 != "expression_r"; (注:timeofday 关键字也支持不等式<、<=、>、>=)。
LDIF 绑定规则关键字表


(更多详细的绑定规则用法,请参阅 Sun ONE Directory Server 5.2 Administration Guide )

ACI样例

  • 1.用户 bjensen 具有修改其自己的目录条目中所有属性的权限。 aci:(target="ldap:///uid=bjensen,dc=example,dc=com")(targetattr=*)(version 3.0; acl "aci1"; allow (write) userdn="ldap:///self";)
  • 2.允许 Engineering Admins 组的成员修改 Engineering 业务类别中所有条目的 departmentNumber 和 manager 属性 aci:(targetattr="departmentNumber || manager")(targetfilter="(businessCategory=Engineering)") (version 3.0; acl "eng-admins-write"; allow (write) groupdn ="ldap:///cn=Engineering Admins, dc=example,dc=com";)
  • 3.允许匿名用户对o=NetscapeRoot下的条目读取和搜索 aci:(targetattr="*")(targetfilter=(o=NetscapeRoot))(version 3.0; acl "Default anonymous access"; allow (read, search) userdn="ldap:///anyone";)
  • 4.向所有经过验证的用户授予对整个树的读取访问,可以在dc=example,dc=com 节点创建下列 ACI: aci:(version 3.0; acl "all-read"; allow (read)userdn="ldap:///all";)
  • 5.允许对整个 example.com 树进行匿名读取和搜索访问,可以在dc=example,dc=com 节点创建下列 ACI: aci:(version 3.0; acl "anonymous-read-search";allow (read, search) userdn = "ldap:///anyone";)
  • 授予Administrators 组对整个目录树写入的权限,则可以在 dc=example,dc=com 节点创建下列 ACI: aci:(version 3.0; acl "Administrators-write"; allow (write) groupdn=ldap:///cn=Administrators,dc=example,dc=com;)
    Java6.0 API for LDAP概述

    从JDK5.0开始,对LDAP协议的数据访问操作就被集成在javax的扩展API包中,并随同JDK一并发布,这一章节,我们主要介绍API包中的类信息。
    javax.naming.directory 包的结构


    常用API解析

    javax.naming.directory.InitialDirContext,初始化目录服务上下文类
    该类是LDAP数据内容的操作工具类,通过该类可以执行绑定LDAP服务器、新增LDAP条目、获取条目实例、修改条目属性、删除条目和根据条件搜索条目等操作。常用方法说明如下:

    初始化LDAP 目录服务上下文(相当于使用JDBC打开一个数据库链接)
    • InitialDirContext(Hashtable<?,?> environment)

    绑定/创建LDAP条目对象(相当于新增一个LDAP条目数据bind(Name
    • name, Object obj, Attributes attrs)
    • bind(String name, Object obj, Attributes attrs)
    • createSubcontext(Name name, Attributes attrs)
    • createSubcontext(String name, Attributes attrs)

    获取条目实例(属性集)
    • getAttributes(Name name)
    • getAttributes(Name name, String[] attrIds)
    • getAttributes(String name)
    • getAttributes(String name, String[] attrIds)

    修改条目属性
    • modifyAttributes(Name name, int mod_op, Attributes attrs)
    • modifyAttributes(Name name, ModificationItem[] mods)
    • modifyAttributes(String name, int mod_op, Attributes attrs)
    • modifyAttributes(String name, ModificationItem[] mods)

    删除条目
    • destroySubcontext(Name name)
    • destroySubcontext(String name)

    根据属性集搜索条目
    • search(Name name, Attributes matchingAttributes)
    • search(Name name, Attributes matchingAttributes, String[] attributesToReturn)
    • search(String name, Attributes matchingAttributes)
    • search(String name, Attributes matchingAttributes, String[] attributesToReturn)

    根据过滤器搜索条目
    • search(Name name, String filterExpr, Object[] filterArgs, SearchControls cons)
    • search(Name name, String filter, SearchControls cons)
    • search(String name, String filterExpr, Object[] filterArgs, SearchControls cons)
    • search(String name, String filter, SearchControls cons)


    javax.naming.directory.BasicAttribute,LDAP基本属性对象
    该类用来表示LDAP条目中的单个属性对象。在目录服务中,每个属性名称是可以对应多个的属性值的。

    构建属性对象
    • BasicAttribute(String id)
    • BasicAttribute(String id, boolean ordered)
    • BasicAttribute(String id, Object value)
    • BasicAttribute(String id, Object value, boolean ordered)

    添加属性值
    • add(int ix, Object attrVal),添加属性值到多值属性的指定位置
    • add(Object attrVal) , 追加属性值到多值属性尾部

    判断属性值是否包含
    • contains(Object attrVal) , 多值属性中有一个值是匹配的,返回true

    获取属性值
    • get(),取得属性值中的一个
    • get(int ix),从多值属性中的指定位置取值

    获取属性ID
    • getID(),属性的ID就是属性名

    删除属性值
    • remove(int ix),删除指定位置的属性值
    • remove(Object attrval),删除指定的属性值


    javax.naming.directory.BasicAttributes,LDAP实体的属性集
    该类表示一个LDAP条目绑定的属性集合,在绝大多数情况下,一个LDAP条目存在多个属性。

    构造属性集
    • BasicAttributes()
    • BasicAttributes(boolean ignoreCase),属性ID是否大小写敏感,建议不要使用敏感
    • BasicAttributes(String attrID, Object val)
    • BasicAttributes(String attrID, Object val, boolean ignoreCase)

    获取属性集中的单个属性对象
    • get(String attrID)

    获取全部属性的枚举
    • getAll()

    获取全部属性的ID枚举
    • getIDs()

    添加新属性
    • put(Attribute attr)
    • put(String attrID, Object val)

    移除指定属性
    • remove(String attrID)


    javax.naming.directory.SearchControls , LDAP目录服务搜索控制对象
    该类负责控制LDAP搜索行为的范围、设定返回结果数上限,搜索耗时上限,指定结果所包括的属性集等。

    设定搜索行为的范围
    • setSearchScope(int scope)

    设定返回结果数上限
    • setCountLimit(long limit)

    设定搜索耗时上限
    • setTimeLimit(int ms) , 以毫秒为单位

    指定结果所包括的属性集
    • setReturningAttributes(String[] attrs)


    javax.naming.directory.SearchResult , 表示.search() 方法的返回结果集中的一项。
    SearchResult类是对LDAP条目属性集的封装。在search()操作中可能返回完整的条目属性,也可能是条目属性的一部分。

    获取SearchResult封装的条目属性
    • getAttributes()


    以上只列举了LDAP操作API的常用部分,更多更详细的描述,请参考 Sun Java6.0 API DOC。LDAP操作代码样例
    在这个章节中,我们将结合LDAP操作的代码实例了解API使用。

    初始化LDAP 目录服务上下文
    该例子中,我们使用uid=linly,ou=People,dc=jsoso,dc=net这个账号,链接位于本机8389端口的LDAP服务器(ldap://localhost:8389),认证方式采用simple类型,即用户名/密码方式。
    1. private static void initialContext() throws NamingException{   
    2.     if(singleton == null){   
    3.         singleton new LDAPConnection();   
    4.           
    5.         //LDAP服务地址   
    6.         singleton.sLDAP_URL "ldap://localhost:8389";    
    7.         //管理员账号   
    8.         singleton.sMANAGER_DN "uid=linly,ou=People,dc=jsoso,dc=net";   
    9.         //管理员密码   
    10.         singleton.sMANAGER_PASSWORD "coffee";   
    11.         //认证类型   
    12.         singleton.sAUTH_TYPE "simple";   
    13.         //JNDI Context工厂类   
    14.         singleton.sCONTEXT_FACTORY "com.sun.jndi.ldap.LdapCtxFactory";    
    15.            
    16.         singleton.envProps.setProperty(Context.INITIAL_CONTEXT_FACTORY, singleton.sCONTEXT_FACTORY);   
    17.         singleton.envProps.setProperty(Context.PROVIDER_URL, singleton.sLDAP_URL);   
    18.         singleton.envProps.setProperty(Context.SECURITY_AUTHENTICATION, singleton.sAUTH_TYPE);   
    19.         singleton.envProps.setProperty(Context.SECURITY_PRINCIPAL, singleton.sMANAGER_DN);   
    20.         singleton.envProps.setProperty(Context.SECURITY_CREDENTIALS, singleton.sMANAGER_PASSWORD);   
    21.           
    22.         singleton.dirCtx new InitialDirContext(singleton.envProps);   
    23.     }   
    24.  
    通过一个Hashtable或者Properties对象为LDAP的Context设置参数,而后初始化InitialDirContext,即可绑定LDAP服务。这相当于JDBC中获取数据库的Connection对象。 

    绑定/创建LDAP条目对象
    用户可以使用bind方法创建新的LDAP条目,下面的代码创建一个DN:"ou=Employee , dc=jsoso ,dc=net"的OrganizationUnit类LDAP条目如下:
    1. public boolean createOrganizationUnit(){   
    2.     String ldapGroupDN "ou=Employee dc=jsoso ,dc=net";   
    3.     try {   
    4.           
    5.         Attributes attrs dirContext.getAttributes(ldapGroupDN);   
    6.         System.out.println("Find the group attributes list :");   
    7.         NamingEnumeration<String>  nEnum attrs.getIDs();               
    8.         for( nEnum.hasMore() ){   
    9.             String attrID nEnum.next();   
    10.             Attribute attr (Attribute)attrs.get(attrID);   
    11.             System.out.println(attr.toString());   
    12.                      
    13.         return false;   
    14.     catch (NamingException e) {   
    15.           
    16.         //创建objectclass属性   
    17.         Attribute objclass new BasicAttribute("objectclass");   
    18.         objclass.add("top");   
    19.         objclass.add("organizationalunit");    
    20.         //创建cn属性   
    21.         Attribute cn new BasicAttribute("ou", "Employee");    
    22.         //创建Attributes,并添加objectclass和cn属性   
    23.         Attributes attrs new BasicAttributes();    
    24.         attrs.put(objclass);    
    25.         attrs.put(cn);    
    26.         //将属性绑定到新的条目上,创建该条目   
    27.         try {   
    28.             dirContext.bind(ldapGroupDN, null, attrs);   
    29.             System.out.println("Group created successful");   
    30.             return true;   
    31.         catch (NamingException e1) {   
    32.             e1.printStackTrace();   
    33.                      
    34.     }   
    35.     return false;   
    36.  
    或者使用createSubcontext方法创建亦可,以下例子我们新增一个inetorgperson类的LDAP条目: 
    Java代码 复制代码
    1. public boolean createOrganizationUnit(){   
    2.     String ldapGroupDN "ou=Employee dc=jsoso ,dc=net";   
    3.     try {   
    4.           
    5.         Attributes attrs dirContext.getAttributes(ldapGroupDN);   
    6.         System.out.println("Find the group attributes list :");   
    7.         NamingEnumeration<String>  nEnum attrs.getIDs();               
    8.         for( nEnum.hasMore() ){   
    9.             String attrID nEnum.next();   
    10.             Attribute attr (Attribute)attrs.get(attrID);   
    11.             System.out.println(attr.toString());   
    12.                      
    13.         return false;   
    14.     catch (NamingException e) {   
    15.           
    16.         //创建objectclass属性   
    17.         Attribute objclass new BasicAttribute("objectclass");   
    18.         objclass.add("top");   
    19.         objclass.add("organizationalunit");    
    20.         //创建cn属性   
    21.         Attribute cn new BasicAttribute("ou", "Employee");    
    22.         //创建Attributes,并添加objectclass和cn属性   
    23.         Attributes attrs new BasicAttributes();    
    24.         attrs.put(objclass);    
    25.         attrs.put(cn);    
    26.         //将属性绑定到新的条目上,创建该条目   
    27.         try {   
    28.             dirContext.bind(ldapGroupDN, null, attrs);   
    29.             System.out.println("Group created successful");   
    30.             return true;   
    31.         catch (NamingException e1) {   
    32.             e1.printStackTrace();   
    33.                      
    34.     }   
    35.     return false;   
    36. }
      获取条目属性
      下面一段代码获取entryDN参数指定条目中的属性集合,并打印到控制台
    Java代码 复制代码
    1.   
    2. public void find(String entryDN){   
    3.     try    
    4.         Attributes attrs dirContext.getAttributes(entryDN);    
    5.         if (attrs != null) {   
    6.             NamingEnumeration<String>  nEnum attrs.getIDs();   
    7.             for( nEnum.hasMore() ){   
    8.                 String attrID nEnum.next();   
    9.                 Attribute attr (Attribute)attrs.get(attrID);   
    10.                 System.out.println(attr.toString());   
    11.             }   
    12.             System.out.println();   
    13.         }else{    
    14.             System.out.println("No found binding.");   
    15.            
    16.     }catch(NamingException ne)    
    17.         ne.printStackTrace();   
    18.        
    19.  

     

    修改条目属性
    修改DN=user.getDistinguishedName()的条目中的cn、givenname、sn和userpassword四个属性值。
    (注:参数DirContext.REPLACE_ATTRIBUTE有另外两个常量:DirContext.ADD_ATTRIBUTE;DirContext.REMOVE_ATTRIBUTE,分别表示新增属性和删除属性。)

    Java代码 复制代码
    1.     
    2. public boolean modifyUser(LDAPUser user) throws Exception    
    3.     //用户对象为空    
    4.     if (user == null)    
    5.         throw new Exception("No user information!n");    
    6.     }   
    7.   
    8.     //检查uid    
    9.     String userDN user.getDistinguishedName();    
    10.     if (userDN == null && userDN.length() == 0   
    11.         throw new NamingException("No userDN you specify!n");    
    12.        
    13.   
    14.     //判断用户条目是否已经存在   
    15.     if(!isUserexist(userDN)){   
    16.         return false;   
    17.     }   
    18.        
    19.     //设置属性    
    20.     Attributes attrs new BasicAttributes();    
    21.     setBasicAttribute(attrs, "cn", user.getCommomName());    
    22.     setBasicAttribute(attrs, "givenname", user.getFirstName());    
    23.     setBasicAttribute(attrs, "sn", user.getLastName());    
    24.     setBasicAttribute(attrs, "userpassword", user.getPassword());      
    25.     //修改属性    
    26.     try{   
    27.         dirContext.modifyAttributes(user.getDistinguishedName(),DirContext.REPLACE_ATTRIBUTE, attrs);    
    28.         System.out.println("User(" user.getDistinguishedName() ") information modified.n");   
    29.         return true;   
    30.     }catch(NamingException ne){   
    31.         ne.printStackTrace();   
    32.     }   
    33.     return false;   
    34. 删除条目
      删除DN= userDN条目

      Java代码 复制代码
      1.   
      2. public boolean deleteUser(String userDN)    
      3.     if(!isUserexist(userDN))    
      4.         return true;   
      5.        
      6.     try {   
      7.         dirContext.destroySubcontext(userDN);   
      8.         System.out.println("User( userDN ") deleted.n");    
      9.         return true;   
      10.     catch (NamingException e) {   
      11.         e.printStackTrace();   
      12.        
      13.     return false;          
      14.  



      根据属性集搜索条目
      根据属性集matchingAttributes中的匹配值,在上下文DN= "ou=People,dc=jsoso ,dc=net"中搜索它的所有子树中的匹配条目。
      (注:SearchControls的SCOPE参数详见SearchControls SCOPE补充说明)

       
      
      Java代码 复制代码
      1.            
      2. public void searchByAttribute(Attributes matchingAttributes){   
      3.      String baseDN "ou=People,dc=jsoso ,dc=net";   
      4.      SearchControls cons new SearchControls();   
      5.      cons.setSearchScope(SearchControls.SUBTREE_SCOPE);   
      6.      try {   
      7.         Name baseName new LdapName(baseDN);   
      8.         NamingEnumeration<SearchResult> ne dirContext.search(baseName, matchingAttributes);   
      9.         SearchResult entry null;   
      10.         for(;ne.hasMore();){   
      11.             entry ne.next();   
      12.             showEntry(entry);   
      13.                              
      14.     catch (NamingException e) {   
      15.         e.printStackTrace();   
      16.     }   
      17.  



      根据过滤器搜索条目
      根据过滤器条件,在上下文DN = "ou=People,dc=jsoso ,dc=net"中,搜索它的所有子树中的匹配条目。
      (注:过滤器filter的相关语法详见LDAP filter语法补充说明)

      Java代码 复制代码
      1.   
      2. public void searchByFilter(String filter){   
      3.      String baseDN "ou=People,dc=jsoso ,dc=net";          
      4.      SearchControls cons new SearchControls();   
      5.      cons.setSearchScope(SearchControls.SUBTREE_SCOPE);   
      6.      try {   
      7.         NamingEnumeration<SearchResult> ne dirContext.search(baseDN, filter cons);   
      8.         SearchResult entry null;   
      9.         for(;ne.hasMore();){   
      10.             entry ne.next();   
      11.             showEntry(entry);   
      12.                              
      13.     catch (NamingException e) {   
      14.         e.printStackTrace();   
      15.     }   
      16.  
        相关补充

        javax.naming.Name对象说明
        在API中,我们常常见到对LDAP上下文条目有两种参数形式,一种是大家都熟悉的String参数,如: String baseDN = "ou=People,dc=jsoso ,dc=net";
        另一种是使用javax.naming.Name类型的参数,那么Name类和String有什么区别呢?
        简 单的说,Name是对String类DN的封装,它把一个完整的DN字窜分解成了RDN的list。这个list的顺序刚好和String相反。就 拿"ou=People,dc=jsoso ,dc=net"为例,Name中的RDN顺序是[0]=net,[1]=jsoso,[2]=People。这样做的好处是更方便对Name进行操作, 比如取其前缀或者后缀。

        SearchControls SCOPE补充说明


        LDAP filter语法补充说明
        filter的运算符

        filter布尔运算符


        搜索过滤器示例
      • 下列过滤器将搜索包含一个或多个 manager 属性值的条目。这也称为存在搜索: manager=*
      • 下列过滤器将搜索包含通用名 Ray Kultgen 的条目。这也称为等价搜索:cn=Ray Kultgen
      • 下列过滤器返回所有不包含通用名 Ray Kultgen 的条目:(!(cn=Ray Kultgen))
      • 下列过滤器返回的所有条目中都有包含子字符串 X.500 的说明属性:description=*X.500*
      • 下列过滤器返回所有组织单元为 Marketing 且说明字段中不包含子字符串 X.500 的条目: (&(ou=Marketing)(!(description=*X.500*)))
      • 下列过滤器返回所有组织单元为 Marketing 且 manager 为 Julie Fulmer 或 Cindy Zwaska 的条目: (&(ou=Marketing)(|(manager=cn=Julie Fulmer,ou=Marketing,dc=siroe,dc=com)(manager=cn=Cindy Zwaska,ou=Marketing,dc=siroe,dc=com)))
      • 下列过滤器返回所有不代表人员的条目: (!(objectClass=person))
      • 下列过滤器返回所有不代表人员且通用名近似于 printer3b 的条目:(&(!(objectClass=person))(cn~=printer3b))

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多