LDAP

LDAP就是 light DAP, 轻量级目录访问协议, 可以想象 还有一个DAP, 
70年代诞生的DAP协议基于 X.400目录访问协议。主要用于 大型主机,因为有大量不常用的功能而且这些不用的功能消耗了过多的系统资源,虽然极强大,但是应用不广, 所以出现了LDAP.

这是一个开放的协议, 具体的实现有 Netscape LDAP, Novell NDS, MS AD等等,这3个是使用最广,影响最大的。
Netscape LDAP server主要使用在unix或类unix系统上, MS AD自然只能在windows上, NDS是唯一一个跨平台的产品。注意: LDAP本身是平台无关的。

工作原因,比较熟悉NDS, AD最熟。我个人最喜欢NDS,AD当然最简单,但是最不稳定,最乱,而且比较耗资源。

楼主说的类似数据库,完全正确,因为它原本就是数据库,只是不是关系型的数据库,它是链式数据库,详细细节可以找本数据库原理,很详细的。

和关系数据库一样, LDAP内能够定义哪些对象,每个对象可以有什么属性,每个属性可以取什么样的值,这样一个框架结构被称为Schema,它是类,对象,属性的集合。类又分为抽象类(只能做父类,不能实例化)和结构类(可以实例化),编程的朋友会发现和面向对象的编程的概念完全一样。

举例: LDAP内必须先有user类, 然后用user类创建user对象(一般缺省有的),我们才能创建具体的用户账号(实例化), schema中user对象被指定了有哪些属性,我们创建账号的时候才能给账号哪些属性,例如 schema中user对象没有别名属性,我们就不能给账号起别名。

Schema的扩展:

缺省的schema一般预先创建有足够的类,对象和属性,例如 MS 的AD 缺省有 170个类和833个对象和属性。但是如果不能满足需要的话,我们就可以扩展Schema, 一般是使用 LDAP API, 例如 MS的 ADSI, NDS有专门的工具,当然也可以直接使用LDAP查询语言,来直接操作整个LDAP目录树。


(前段时间一直在做LDAP+POSTFIX相关项目,先把关于LDAP的一些经验写出来,一来可能会帮助一些人,二来对我自己所学知识也是一个巩固。) 

先声明:我写的只是我对LDAP的一些理解,如果我的理解错误,那就是对兄弟们的误导。所以你可以直接看文章的结尾提供的几个网址。 

关于LDAP的概念随便网上有很多,我不想重复,这里只是说一下我自己的理解。 
都说它是“轻量级目录协议”,太专业,我不懂,我只把它想象成“简单”的目录协议。 

几个很重要的概念,以后会用到: 
--------------------------------------------- 
dn :一条记录的位置 
dc :一条记录所属区域 
ou :一条记录所属组织 
cn/uid:一条记录的名字/ID 
--------------------------------------------- 

实际上更多时候我只把它看成数据库。我把它和我非常熟悉的MYSQL数据库做比较,通常会得到更好的理解: 

MYSQL用“表”储存数据,LDAP用“树” 
MYSQL指定一条记录要3个条件:DB、TABLE、ROW。 
LDAP却更自由,为什么呢?因为LDAP数据是“树”状的,而且这棵树是可以无限延伸的,假设你要树上的一个苹果(一条记录),你怎么告诉园丁它的位置呢?当然首先要说明是哪一棵树(dc,相当于MYSQL的DB),然后是从树根到那个苹果所经过的所有“分叉”(ou,呵呵MYSQL里面好象没有这DD),最后就是这个苹果的名字(uid,记得我们设计MYSQL或其它数据库表时,通常为了方便管理而加上一个‘id’字段吗?)。 好了!这时我们可以清晰的指明这个苹果的位置了,就是那棵“歪脖树”的东边那个分叉上的靠西边那个分叉的再靠北边的分叉上的半红半绿的……,晕了!你直接爬上去吧!我还是说说LDAP里要怎么定义一个字段的位置吧,树(dc=waibo,dc=com),分叉(ou=bei,ou=xi,ou=dong),苹果(cn=honglv),好了!位置出来了: 
dn:cn=honglv,ou=bei,ou=xi,ou=dong,dc=waibo,dc=com 

一个有名的画家说过:“世上没有相同的2个鸡蛋”。当然也没有相同的2个苹果……,同样,在LDAP里也不可能存在2个相同的dn。 


LDAP数据填充原理: 
一棵树的生长,要循序渐进,如果还没有长出某个分叉,就不可能在那个分叉里长出苹果(问:FT!苹果是长在分叉上的吗?答:为了便于理解,你就当它是吧),同样,LDAP数据库也要一步步的充实,举一个学校数据库的例子,我们将要把一个庞大的学生档案放到LDAP里,大致需要这么做: 
--------------------------------------------- 
1、建立“树根”,这是通过修改“slapd.conf”来实现的,由于现在的目的是理解,所以具体步骤就不说了,反正就是在这一步建立了一个“dc=ourschool,dc=org”这样一个“树根”。 注意:我把它理解成“目录”,或者“容器”,甚至它本身也是文件(苹果)的特殊形式,熟悉LINUX文件系统的朋友会更容易理解。 
2、建立18个系,分别是“dn:ou=computer,dc=ourschool,dc=org”、“dn:ou=film,dc=ourschool,dc=org”…… 
3、当然是在每个系里面建立专业,比如“dn:ou=linux,ou=computer,dc=ourschool,dc=org”…… 
4、(开始长苹果吧!)加学生喽——“dn:cn=stan,ou=linux,ou=computer,dc=ourschool,dc=org”…… 
5、已经完成了吗?对了!学生的详细信息还没有呐!不过先这样吧,反正记录是可以编辑的。 
--------------------------------------------- 


LDAP记录的详细信息 
dn:cn=stan,ou=linux,ou=computer,dc=ourschool,dc=org 
objectClass:organizationalPerson 
cn:stan 
cn:小刀 
sn:小刀 
description:a good boy 
(以上是一条记录的信息,如果把他保存成LDIF文件,可以导入到LDAP数据库中) 
上面不是说没有学生详细信息吗?怕你着急,就马上写出来了,只是还没有导入到LDAP里,那是以后的事。这里我先就你可能会产生的疑问做回答。 
--------------------------------------------- 
Q1:“cn”不是在“dn”里定义了吗,怎么又在后面重新定义了? 答:你要把“cn=stan,ou=linux,ou=computer,dc=ourschool,dc=org”看成是一个整体,它只是属性dn的值。 
Q2:怎么后面有2个“cn”,我以哪个为准? 答:区别于普通数据库,LDAP每个属性一般可以具有多个值,这样不好吗?你在学校数据库里找我的时候,只要记得我的一个cn就可以了,用“cn=stan”或“cn=小刀”都可以找到我! 
Q3:就这些属性了吗?我都不知道你是男是女。 答:先声明,偶是男地。 LDAP对记录的属性做了严格的限制(这一点我不太喜欢),也就是说,你可以用哪些属性,哪些属性不能为空,哪些属性最多只能有一个值等,他们都给你规定好了。 幸好你有选择的权利,比如这次我们是储存学生信息,那么我们就定义一个“objectClass:organizationalPerson”,这样“organizationalPerson”这个类所规定的所有属性我们都可以用了,而且确实很适合我们。 虽然这个类中没有“sex”这个属性,不过你完全可以用一个“空闲”的属性来顶替。 如果我们能自己建立“类”就更好了,但目前我还没有时间去研究这个东西,我也期望高手指点啊 :) 
--------------------------------------------- 


好了!看到我贴的图了吗?那是我偷别人的,差不多能用我就不自己画了 :) 

############################################################## 

关于安装配置LDAP,使之储存系统用户,这里有一个非常好的网址,如果你的英文不是很差,都应该做的来,我偷个懒,就先不写这方面的东西喽: 
http://www.mandrakesecure.net/en/docs/ldap-auth.php 
上面的方法我已经试过,是可行的,如果兄弟们配置的时候出现问题我们可以讨论讨论。 

关于LDAP+POSTFIX,POSTFIX里的“LDAP_README”中介绍的很详细,我再说就是重复了。 
############################################################## 
其它相关资源: 
yala (很实用的数据库操作工具,简单的说,他就是MYSQL的phpmyadmin,自己找下载地址吧~) 
http://www.openldap.org/ (说实话,我一直没用上它,不过它是官方网站,不提也不好) 
http://ldap.akbkhome.com/ (什么‘类’下面有什么‘属性’,在这里找)



1. 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)属性,但也可以包含可选的如邮件,电话号码等属性。

 

2. LDAP简称对应

  1. o– organization(组织-公司)
  2. ou – organization unit(组织单元-部门)
  3. c - countryName(国家)
  4. dc - domainComponent(域名)
  5. sn – suer name(真实名称)
  6. cn - common name(常用名称)

 

3. 目录设计

设计目录结构是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: headhauncho@acme.com

    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: jonesrd@acme.com

    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: woodses@acme.com

    localityName: Houston

 

 

4. 配置OpenLDAP

本文实践了在 Windows 下安装配 openldap,并添加一个条目,LdapBrowser 浏览,及 Java 程序连接 openldap 的全过程。

 

1. 下载安装 openldap for windows,当前版本2.2.29下载地址:http://download.bergmans.us/openldap/openldap-2.2.29/openldap-2.2.29-db-4.3.29-openssl-0.9.8a-win32_Setup.exe

    相关链接:http://lucas.bergmans.us/hacks/openldap/

   安装很简单,一路 next 即可,假设我们安装在 c:\openldap

 

2. 配置 openldap,编辑 sldap.conf 文件

   1) 打开 c:\openldap\sldap.conf,找到

    include  C:/openldap/etc/schema/core.schema,在它后面添加

    include  C:/openldap/etc/schema/cosine.schema

    include  C:/openldap/etc/schema/inetorgperson.schema

 

    接下来的例子只需要用到以上三个 schema,当然,如果你觉得需要的话,你可以把其他的 schema 全部添加进来

    include  C:/openldap/etc/schema/corba.schema

    include  C:/openldap/etc/schema/dyngroup.schema

    include  C:/openldap/etc/schema/java.schema

    include  C:/openldap/etc/schema/misc.schema

    include  C:/openldap/etc/schema/nis.schema

    include  C:/openldap/etc/schema/openldap.schema

 

   2) 还是在 sldap.conf 文件中,找到

    suffix  "dc=my-domain,dc=com"

    rootdn  "cn=Manager,dc=my-domain,dc=com"

    把这两行改为

    suffix "o=teemlink,c=cn" 

    rootdn "cn=Manager,o=teemlink,dc=cn"

 

    suffix 就是看自己如何定义了,后面步骤的 ldif 文件就必须与它定义了。还要注意到这个配置文件中有一个 rootpw  secret,这个 secret 是 cn=Manager 的密码,以后会用到,不过这里是明文密码,你可以用命令: slappasswd -h {MD5} -s secret 算出加密的密码 {MD5}Xr4ilOzQ4PCOq3aQ0qbuaQ== 取代配置中的 secret。

 

3. 启动 openldap

    CMD 进入到 c:\openldap 下,运行命令 sldapd -d 1

    用可以看到控制台下打印一片信息,openldap 默认是用的 Berkeley DB 数据库存储目录数据的。

 

4. 建立条目,编辑导入 ldif 文件

   1) 新建一个 ldif(LDAP Data Interchanged Format) 文件(纯文本格式),例如 test.ldif,文件内容如下:

   

dn: o=teemlink

objectclass: top

objectclass: organization

o: develop

 

   2) 执行命令:ldapadd -l test.ldif

 

5. 使用LDAP Browser进行访问

       5.1安装LDAP Browser2.6软件,进行如下操作:

    

  

 

5.2显示效果

  

 

5. Java操作LDAP

 

5.1 用JNDI进访问

复制代码
  
  
package cn.myapps.test; import java.util.Hashtable; import javax.naming.Context; import javax.naming.NamingException; import javax.naming.directory.Attributes; import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; public class LdapTest { public void JNDILookup() { String root = " o=teemlink,c=cn " ; Hashtable env = new Hashtable(); env.put(Context.INITIAL_CONTEXT_FACTORY, " com.sun.jndi.ldap.LdapCtxFactory " ); env.put(Context.PROVIDER_URL, " ldap://192.168.0.30/ " + root); env.put(Context.SECURITY_AUTHENTICATION, " simple " ); env.put(Context.SECURITY_PRINCIPAL, " cn=Nicholas,ou=产品,o=teemlink,c=cn " ); env.put(Context.SECURITY_CREDENTIALS, " 123456 " ); DirContext ctx = null ; try { ctx = new InitialDirContext(env); Attributes attrs = ctx.getAttributes( " cn=Nicholas,ou=产品 " ); System.out.println( " Last Name: " + attrs.get( " sn " ).get()); System.out.println( " 认证成功 " ); } catch (javax.naming.AuthenticationException e) { e.printStackTrace(); System.out.println( " 认证失败 " ); } catch (Exception e) { System.out.println( " 认证出错: " ); e.printStackTrace(); } if (ctx != null ) { try { ctx.close(); } catch (NamingException e) { // ignore } } } public static void main(String[] args) { LdapTest LDAPTest = new LdapTest(); LDAPTest.JNDILookup(); } }
复制代码

 

5.2 用JLDAP进访问

访问地址:http://www.openldap.org/jldap/ 并下载相关lib

 

复制代码
  
  
import com.novell.ldap. * ; import java.io.UnsupportedEncodingException; public class List { public static void main(String[] args) { int ldapPort = LDAPConnection.DEFAULT_PORT; int searchScope = LDAPConnection.SCOPE_ONE; int ldapVersion = LDAPConnection.LDAP_V3; boolean attributeOnly = false ; String attrs[] = null ; String ldapHost = " 192.168.0.30 " ; String loginDN = " cn=Manager,o=teemlink,c=cn " ; String password = " secret " ; String searchBase = " ou=develop,o=teemlink,c=cn " ; String searchFilter = " objectClass=* " ; LDAPConnection lc = new LDAPConnection(); try { // connect to the server lc.connect(ldapHost, ldapPort); // bind to the server lc.bind(ldapVersion, loginDN, password.getBytes( " UTF8 " )); LDAPSearchResults searchResults = lc.search(searchBase, // container to search searchScope, // search scope searchFilter, // search filter attrs, // "1.1" returns entry name only attributeOnly); // no attributes are returned // print out all the objects while (searchResults.hasMore()) { LDAPEntry nextEntry = null ; try { nextEntry = searchResults.next(); System.out.println( " \n " + nextEntry.getDN()); System.out.println(nextEntry.getAttributeSet()); } catch (LDAPException e) { System.out.println( " Error: " + e.toString()); // Exception is thrown, go for next entry continue ; } } // disconnect with the server lc.disconnect(); } catch (LDAPException e) { System.out.println( " Error: " + e.toString()); } catch (UnsupportedEncodingException e) { System.out.println( " Error: " + e.toString()); } System.exit( 0 ); } }
复制代码

 

5.3 用JDBC-LDAP进访问

访问地址:http://www.openldap.org/jdbcldap/ 并下载相关lib

 

复制代码
  
  
package jdbcldap; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.Statement; public class JdbcLdap { /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { Class.forName( " com.octetstring.jdbcLdap.sql.JdbcLdapDriver " ); String ldapConnectString = " jdbc:ldap://192.168.0.30/o=teemlink,c=cn?SEARCH_SCOPE:=subTreeScope " ; Connection con = DriverManager.getConnection(ldapConnectString, " cn=Manager,o=teemlink,c=cn " , " secret " ); String sql = " SELECT * FROM ou=develop,o=teemlink,c=cn " ; Statement sat = con.createStatement(); ResultSet rs = sta.executeQuery(sql); while (rs.next()) { System.out.println(rs.getString( 1 )); } if (con != null ) con.close(); } }
复制代码

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值