2023年6月21日发(作者:)

Microsoft LDAP 错误代码Microsoft Windows 2000 Active Directory 使用 Internet 标准的轻量级目录访问协议 (LDAP)

来访问信息。在响应各种 LDAP 请求时,域控制器会返回包含域 LDAP 错误代码的响应,这些错误代码指示协议操作的状态。本文将介绍这些错误代码。下表描述了这些错误代码。

代码 值 说明---------------------------------------------------------------------------LDAP_SUCCESS 0x00 请求成功。Sucessful _OPERATIONS_ERROR 0x01 LDAP 库初始化失败。Intialization of

LDAP library _PROTOCOL_ERROR 0x02 出现协议错误。Protocol error _TIMELIMIT_EXCEEDED 0x03 超出时间限制。Time limit has _SIZELIMIT_EXCEEDED 0x04 超出大小限制。Size limit has _COMPARE_FALSE 0x05 比较结果为 FALSE。Compare yielded _COMPARE_TRUE 0x06 比较结果为 TRUE。Compare yielded _AUTH_METHOD_NOT_SUPPORTED 0x07 不支持此身份验证方法。The

authentication method is not _STRONG_AUTH_REQUIRED 0x08 需要加强的身份验证。Strong authentication is

_REFERRAL_V2 0x09 LDAP 版本 2 检索。LDAP version 2 _PARTIAL_RESULTS 0x09 接收到部分结果和检索。Partial results and referrals _REFERRAL 0x0a 出现检索。Referral _ADMIN_LIMIT_EXCEEDED 0x0b 超出服务器上的管理限制。Administration limit on

the server has _UNAVAILABLE_CRIT_EXTENSION 0x0c 没有精密扩展。Critical extension is

_CONFIDENTIALITY_REQUIRED 0x0d 需要保密。Confidentiality is _NO_SUCH_ATTRIBUTE 0x10 请求的属性不存在。Requested attribute does not _UNDEFINED_TYPE 0x11 类型未定义。The type is not _INAPPROPRIATE_MATCHING 0x12 出现不适当的匹配。 An inappropriate matching

_CONSTRAINT_VIOLATION 0x13 出现约束冲突。A constraint violation _ATTRIBUTE_OR_VALUE_EXISTS 0x14 属性已存在或已被赋值。The attribute exists

or the value has been _INVALID_SYNTAX 0x15 语法无效。The syntax is _NO_SUCH_OBJECT 0x20 对象不存在。Object does not _ALIAS_PROBLEM 0x21 别名无效。The alias is _INVALID_DN_SYNTAX 0x22 辨别名的语法无效。The distinguished name has an

invalid _IS_LEAF 0x23 该对象为叶对象。The object is a _ALIAS_DEREF_PROBLEM 0x24 无法取消对别名的引用。Cannot de-reference the

_INAPPROPRIATE_AUTH 0x30 身份验证不正确。Authentication is _INVALID_CREDENTIALS 0x31 提供的凭据无效。The supplied credential is _INSUFFICIENT_RIGHTS 0x32 用户无足够的访问权限。The user has insufficient access

_BUSY 0x33 服务器忙。The server is _UNAVAILABLE 0x34 服务器不可用。The server is _UNWILLING_TO_PERFORM 0x35 服务器不处理目录请求。The server does not handle

directory _LOOP_DETECT 0x36 引用链循环回至引用服务器。The chain of referrals has looped

back to a referring _NAMING_VIOLATION 0x40 存在命名冲突。There was a naming _OBJECT_CLASS_VIOLATION 0x41 存在对象类别冲突。There was an object class

_NOT_ALLOWED_ON_NONLEAF 0x42 不允许在非叶对象上操作。Operation is not

allowed on a non-leaf _NOT_ALLOWED_ON_RDN 0x43 不允许在 RDN 上操作。Operation is not allowed on

_ALREADY_EXISTS 0x44 对象已存在。The object already _NO_OBJECT_CLASS_MODS 0x45 无法修改对象类别。Cannot modify object _RESULTS_TOO_LARGE 0x46 返回的结果太大。Results returned are too _AFFECTS_MULTIPLE_DSAS 0x47 多个目录服务代理受到影响。Multiple directory

service agents are _OTHER 0x50 出现未知错误。Unknown error _SERVER_DOWN 0x51 无法联系 LDAP 服务器。Cannot contact the LDAP _LOCAL_ERROR 0x52 出现本地错误。Local error _ENCODING_ERROR 0x53 出现编码错误。Encoding error _DECODING_ERROR 0x54 出现解码错误。Decoding error _TIMEOUT 0x55 搜索超时。The search was timed _AUTH_UNKNOWN 0x56 出现未知的身份验证错误。Unknown authentication error

_FILTER_ERROR 0x57 搜索筛选器不正确。The search filter is _USER_CANCELLED 0x58 用户已取消操作。The user has canceled the _PARAM_ERROR 0x59 传递给例程的参数不正确。An incorrect parameter was passed to

a _NO_MEMORY 0x5a 系统内存不足。The system is out of _CONNECT_ERROR 0x5b 无法建立到服务器的连接。Cannot establish a connection to

the _NOT_SUPPORTED 0x5c 不支持此功能。The feature is not _CONTROL_NOT_FOUND 0x5d ldap 函数找不到指定控件。The ldap function did not

find the specified _NO_RESULTS_RETURNED 0x5e 不支持此功能。The feature is not _MORE_RESULTS_TO_RETURN 0x5f 将返回其他结果。Additional results are to be

_CLIENT_LOOP 0x60 检测到客户循环。Client loop was _REFERRAL_LIMIT_EXCEEDED 0x61 超出检索限制。The referral limit was _SASL_BIND_IN_PROGRESS 0x0E 多阶段绑定的中间绑定结果 Intermediary bind

result for multi-stage

完------------------------------------------------------------LDAP介绍1. LDAP介绍 41.1. LDAP是什么 41.2. LDAP是电话簿 41.3. LDAP是不是数据库 42. LDAP的特点 52.1. LDAP的优势 52.1.1 跨平台 52.1.2 费用及维护 52.1.3 复制技术 52.1.4 允许使用ACI 52.2. LDAP存储什么数据 62.3. 什么时候该用LDAP存储数据 63. LDAP的基本模型 73.1 信息模型:描述LDAP的信息表示方式 73.2 命名模型:描述LDAP中的数据如何组织 73.3 功能模型:描述LDAP中的数据操作访问 73.4 安全模型:描述LDAP中的安全机制 83.4.1 身份认证 83.4.2 通讯安全 83.4.3 访问控制 84. LDAP数据结构 94.1 树状组织 94.2 条目和条目认证 94.3 数据样式(schema) 94.4 对象类型(objectClass) 94.5 过滤器和语法 104.6 树移植 104.7 LDIF交换文件 104.8 JAVA或CORBA对象串行化存储 101.1. LDAP是什么LDAP是轻量目录访问协议,英文全称是Lightweight Directory Access Protocol,一般都简称为LDAP。它是基于X.500标准的,但是简单多了并且可以根据需要定制。与X.500不同,LDAP支持TCP/IP,这对访问Internet是必须的。LDAP的核心规范在RFC中都有定义,所有与LDAP相关的RFC都可以在LDAPman RFC网页中找到。简单说来,LDAP是一个得到关于人或者资源的集中、静态数据的快速方式。

LDAP是一个用来发布目录信息到许多不同资源的协议。通常它都作为一个集中的地址本使用,不过根据组织者的需要,它可以做得更加强大。

1.2. LDAP是电话簿LDAP其实是一电话簿,类似于我们所使用诸如NIS(Network Information Service)、DNS

(Domain Name Service)等网络目录,也类似于你在花园中所看到的树木。

1.3. LDAP是不是数据库不少LDAP开发人员喜欢把LDAP与关系数据库相比,认为是另一种的存贮方式,然后在读性能上进行比较。实际上,这种对比的基础是错误的。LDAP和关系数据库是两种不同层次的概念,后者是存贮方式(同一层次如网格数据库,对象数据库),前者是存贮模式和访问协议。LDAP是一个比关系数据库抽象层次更高的存贮概念,与关系数据库的查询语言SQL属同一级别。LDAP最基本的形式是一个连接数据库的标准方式。该数据库为读查询作了优化。因此它可以很快地得到查询结果,不过在其它方面,例如更新,就慢得多。从另一个意义上 LDAP是实现了指定的数据结构的存贮,它是一种特殊的数据库。但是LDAP和一般的数据库不同,明白这一点是很重要的。 LDAP对查询进行了优化,与写性能相比LDAP的读性能要优秀很多。就象Sybase、Oracle、Informix或Microsoft的数据库管理系统(DBMS)是用于处理查询和更新关系型数据库那样,LDAP服务器也是用来处理查询和更新LDAP目录的。换句话来说LDAP目录也是一种类型的数据库,但不是关系型数据库。要特别注意的是,LDAP通常作为一个hierarchal数据库使用,而不是一个关系数据库。因此,它的结构用树来表示比用表格好。正因为这样,就不能用SQL语句了。

2. LDAP的特点2.1. LDAP的优势2.1.1 跨平台LDAP最大的优势是:可以在任何计算机平台上,用很容易获得的而且数目不断增加的LDAP的客户端程序访问LDAP目录。而且也很容易定制应用程序为它加上LDAP的支持。LDAP协议是跨平台的和标准的协议,因此应用程序就不用为LDAP目录放在什么样的服务器上操心了。实际上,LDAP得到了业界的广泛认可,因为它是Internet的标准。产商都很愿意在产品中加入对LDAP的支持,因为他们根本不用考虑另一端(客户端或服务端)是怎么样的。LDAP服务器可以是任何一个开发源代码或商用的LDAP目录服务器(或者还可能是具有LDAP界面的关系型数据库),因为可以用同样的协议、客户端连接软件包和查询命令与LDAP服务器进行交互。与LDAP不同的是,如果软件产商想在软件产品中集成对DBMS的支持,那么通常都要对每一个数据库服务器单独定制。2.1.2 费用及维护不象很多商用的关系型数据库,你不必为LDAP的每一个客户端连接或许可协议付费。大多数的LDAP服务器安装起来很简单,也容易维护和优化。2.1.3 复制技术LDAP服务器可以用"推"或"拉"的方法复制部分或全部数据,例如:可以把数据"推"到远程的办公室,以增加数据的安全性。复制技术是内置在LDAP服务器中的而且很容易配置。如果要在DBMS中使用相同的复制功能,数据库产商就会要你支付额外的费用,而且也很难管理。2.1.4 允许使用ACILDAP允许你根据需要使用ACI(一般都称为ACL或者访问控制列表)控制对数据读和写的权限。例如,设备管理员可以有权改变员工的工作地点和办公室号码,但是不允许改变记录中其它的域。ACI可以根据谁访问数据、访问什么数据、数据存在什么地方以及其它对数据进行访问控制。因为这些都是由LDAP目录服务器完成的,所以不用担心在客户端的应用程序上是否要进行安全检查。2.2. LDAP存储什么数据LDAP对于这样存储这样的信息最为有用:也就是数据需要从不同的地点读取,但是不需要经常更新。例如,这些信息存储在LDAP目录中是十分有效的:l 公司员工的电话号码簿和组织结构图l 客户的联系信息l 计算机管理需要的信息,包括NIS映射、email假名,等等l 软件包的配置信息l 公用证书和安全密匙2.3. 什么时候该用LDAP存储数据大多数的LDAP服务器都为读密集型的操作进行专门的优化。因此,当从LDAP服务器中读取数据的时候会比从专门为OLTP优化的关系型数据库中读取数据快一个数量级。也是因为专门为读的性能进行优化,大多数的LDAP目录服务器并不适合存储需要需要经常改变的数据。例如,用LDAP服务器来存储电话号码是一个很好的选择,但是它不能作为电子商务站点的数据库服务器。如果下面每一个问题的答案都是"是",那么把数据存在LDAP中就是一个好主意。l 需要在任何平台上都能读取数据吗?l 每一个单独的记录项是不是每一天都只有很少的改变?l 可以把数据存在平面数据库(flat database)而不是关系型数据库中吗?换句话来说,也就是不管什么范式不范式的,把所有东西都存在一个记录中(差不多只要满足第一范式)。最后一个问题可能会唬住一些人,其实用平面数据库去存储一些关系型的数据也是很一般的。例如,一条公司员工的记录就可以包含经理的登录名。用LDAP来存储这类信息是很方便的。一个简单的判断方法:如果可以把保数据存在一张张的卡片里,就可以很容易地把它存在LDAP目录里。3. LDAP的基本模型

3.1 信息模型:描述LDAP的信息表示方式

在LDAP中信息以树状方式组织,在树状信息中的基本数据单元是条目,而每个条目由属性构成,属性中存储有属性值;LDAP中的信息模式,类似于面向对象的概念,在LDAP中每个条目必须属于某个或多个对象类(Object Class),每个Object Class由多个属性类型组成,每个属性类型有所对应的语法和匹配规则;对象类和属性类型的定义均可以使用继承的概念。每个条目创建时,必须定义所属的对象类,必须提供对象类中的必选属性类型的属性值,在LDAP中一个属性类型可以对应多个值。

在LDAP中把对象类、属性类型、语法和匹配规则统称为Schema,在LDAP中有许多系统对象类、属性类型、语法和匹配规则,这些系统Schema在LDAP标准中进行了规定,同时不同的应用领域也定义了自己的Schema,同时用户在应用时,也可以根据需要自定义Schema。这有些类似于XML,除了XML标准中的XML定义外,每个行业都有自己标准的DTD或DOM定义,用户也可以自扩展;也如同XML,在LDAP中也鼓励用户尽量使用标准的Schema,以增强信息的互联互通。

在Schema中最难理解的是匹配规则,这是LDAP中为了加快查询的速度,针对不同的数据类型,可以提供不同的匹配方法,如针对字符串类型的相等、模糊、大于小于均提供自己的匹配规则。

3.2 命名模型:描述LDAP中的数据如何组织

LDAP中的命名模型,也即LDAP中的条目定位方式。在LDAP中每个条目均有自己的DN和RDN。DN是该条目在整个树中的唯一名称标识,RDN是条目在父节点下的唯一名称标识,如同文件系统中,带路径的文件名就是DN,文件名就是RDN。

3.3 功能模型:描述LDAP中的数据操作访问

在LDAP中共有四类10种操作:查询类操作,如搜索、比较;更新类操作,如添加条目、删除条目、修改条目、修改条目名;认证类操作,如绑定、解绑定;其它操作,如放弃和扩展操作。除了扩展操作,另外9种是LDAP的标准操作;扩展操作是LDAP中为了增加新的功能,提供的一种标准的扩展框架,当前已经成为LDAP标准的扩展操作,有修改密码和StartTLS扩展,在新的RFC标准和草案中正在增加一些新的扩展操作,不同的LDAP厂商也均定义了自己的扩展操作。

3.4 安全模型:描述LDAP中的安全机制

LDAP中的安全模型主要通过身份认证、安全通道和访问控制来实现。

3.4.1 身份认证在LDAP中提供三种认证机制,即匿名、基本认证和SASL(Simple Authentication and

Secure Layer)认证。匿名认证即不对用户进行认证,该方法仅对完全公开的方式适用;基本认证均是通过用户名和密码进行身份识别,又分为简单密码和摘要密码认证;SASL认证即LDAP提供的在SSL和TLS安全通道基础上进行的身份认证,包括数字证书的认证。

3.4.2 通讯安全在LDAP中提供了基于SSL/TLS的通讯安全保障。SSL/TLS是基于PKI信息安全技术,是目前Internet上广泛采用的安全服务。LDAP通过StartTLS方式启动TLS服务,可以提供通讯中的数据保密性、完整性保护;通过强制客户端证书认证的TLS服务,同时可以实现对客户端身份和服务器端身份的双向验证。

3.4.3 访问控制虽然LDAP目前并无访问控制的标准,但从一些草案中或是事实上LDAP产品的访问控制情况,我们不难看出:LDAP访问控制异常的灵活和丰富,在LDAP中是基于访问控制策略语句来实现访问控制的,这不同于现有的关系型数据库系统和应用系统,它是通过基于访问控制列表来实现的,无论是基于组模式或角色模式,都摆脱不了这种限制。

在使用关系型数据库系统开发应用时,往往是通过几个固定的数据库用户名访问数据库。对于应用系统本身的访问控制,通常是需要建立专门的用户表,在应用系统内开发针对不同用户的访问控制授权代码,这样一旦访问控制策略变更时,往往需要代码进行变更。总之一句话,关系型数据库的应用中用户数据管理和数据库访问标识是分离的,复杂的数据访问控制需要通过应用来实现。

而对于LDAP,用户数据管理和访问标识是一体的,应用不需要关心访问控制的实现。这是由于在LDAP中的访问控制语句是基于策略语句来实现的,无论是访问控制的数据对象,还是访问控制的主体对象,均是与这些对象在树中的位置和对象本身的数据特征相关。

在LDAP中,可以把整个目录、目录的子树、制定条目、特定条目属性集或符合某过滤条件的条目作为控制对象进行授权;可以把特定用户、属于特定组或所有目录用户作为授权主体进行授权;最后,还可以定义对特定位置(例如IP地址或DNS名称)的访问权。

4. LDAP数据结构LDAP是实现了指定的数据结构的存贮,它包括以下可以用关系数据库实现的结构要求:树状组织、条目认证、类型定义、许可树形记录拷贝。4.1 树状组织无论是X500还是LDAP都是采用树状方式进行记录。每一个树目录都有一个树根的入口条目,子记录全部是这一根条目的子孙。这是目录与关系数据类型最大的区别(关系数据库的应用结构也可实现树状记录)。因此,把目录看作是更高级的树状数据库也未尝不可,只不过除此外,它不能实现关系存贮的重要功能。4.2 条目和条目认证LDAP是以条目作为认证的根据。ROOT的权限认证与目录本身无关,但除此外所有条目的认证权限由条目本身的密码进行认证。LDAP可以配置成各种各样不同的父子条目权限继承方式。每一个条目相当于一个单一的平面文本记录,由条目自身或指定的条目认证进行访问控制。因此,LDAP定义的存贮结构等同于一批树状组织的平面数据库,并提供相应的访问控制。条目中的记录以名-值对的形式存在,每一个名值对必须由数据样式schema预定义。因此,LDAP可以看作是以规定的值类型以名值对形式存贮在一系列以树状组织的平面数据库的记录的集合。4.3 数据样式(schema)数据样式schema是针对不同的应用,由用户指定(设计)类和属性类型预定义,条目中的类(objectclass)和属性必须在在LDAP服务器启动时载入内存的schema已有定义。因此,AD活动目录中的条目记录就必须符合Active Directory的schema中。如果已提供的schema中的定义不够用,用户可以自行定义新的schema.在/ 中可以看到常用的schema。4.4 对象类型(objectClass)因为LDAP目录可以定制成存储任何文本或二进制数据,到底存什么要由你自己决定。LDAP目录用对象类型(objectclass)的概念来定义运行哪一类的对象使用什么属性。在几乎所有的LDAP服务器中,你都要根据自己的需要扩展基本的LDAP目录的功能,创建新的对象类型或者扩展现存的对象类型。条目中的记录通过objectclass实现分类,objectClass是一个继承性的类定义,每一个类定义指定必须具备的属性。如某一条目指定必须符合某个类型,则它必须具备超类所指定的属性。通过objectclass分类,分散的条目中的记录就实际上建立了一个索引结构,为高速的读查询打下了基础。Objectclass也是过滤器的主要查询对象。4.5 过滤器和语法LDAP是一个查询为主的记录结构,无论是何种查询方式,最终都由过滤器缺点查询的条件。过滤器相当于SQL中的WHERE子句。任何LDAP的类过滤和字符串都必须放在括号内,如(objectclass=*),指列出所有类型的记录(不过分类)。可以使用=,>=,<=,~=(约等于)进行比较,如(number<=100)。合并条件是最怪的,必须把操作符放在两个操作对象的前面而不是中间,单一操作对象用括号括起来。如l A与B,不是A&B,而是(&(A)(B))。l 或使用"|"表示;l 非使用"!"表示。l 对于"与",或"或"在操作符后可以跟多个条件表达式,但非后则只参是单个表达式。详见RFC1558。4.6 树移植LDAP最重要的特性和要求并不是读性能,而是扩展性。这一特性是通过树移植和树复制实现的。按LDAP的RFC要求,LDAP目录应该可以任意地在不同的目录间连接、合并并实现自动复制,及自动性同步。这意味着用户可以在任一LDAP中访问条目,而不用管其中某一部分是否复制自全世界另一目录中的记录,同时另一目录中的记录同样在正常运作。这一特性如果在关系数据库中实现,意味着要使用程序化的非规范化预复制。类似于汇总帐目的设计。4.7 LDIF交换文件LDIF是LDAP约定的记录交换格式,以平面文本的形式存在,是大部分LDAP内容交换的基础,如拷贝、添加、修改等操作,都是基于LDIF文件进行操作。4.8 JAVA或CORBA对象串行化存储网络高效率的访问加上JAVA的跨平台能力,当把JAVA或CORBA对象串行化后存储到LDAP目录上时,可以产生非同一般的集成效果--实际上,这正是EJB和.NET的网络定位基础技术。使用JAVA或CORBA对象存储时,必须首先让LDAP服务支持该对象定义,也就是说包含或。JAVA必须存储在objectclass=javacontainer的条目中,而且必须带有cn属性,这意味着除非该JAVA类专门实现了DirContext接口,对于大多数JAVA类来说,只能采用DirContext代替Context实现bind的添加操作。取出JAVA类相对要简单得多,只需使用()获得该对象的句柄,然后强制造型成所需要的对象就可以了,如:Person p=(Person)("cn=elvis,dc=daifu,dc=com");这个句法在EJB的程序中,是经常用到的。使用CORBA的跨语言性质,使用CORBA存储对象比JAVA更加诱人,这意味着所存储的对象可以被任何语言编写的客户端访问。其实,微软的.net说到底也非常简单,无非是把COM对象存储到微软自家的目录ActiveDirectory里面,从而可以在网络范围内使用任何微软平台的语言进行对象访问而已。众所周知,COM就是与CORBA相对的微软规范。使用对象串行化技术,可以把常用对象如某个打印机,某个客户直接存储到LDAP中,然后快速获取该对象的引用,这样,就比把对象信息存储到关系数据库中,分别取出属性,然后再初始化对象操作的做法,效率要高得多了。这是LDAP目前比普通关系数据库存储要优秀的地方,而对象数据库还不成熟NET下ActiveDirectory编程技术普通目录及其面临的困难 谈到计算机目录及其相关技术,总能让我们想到无时不在使用的文件系统目录、灵巧实用的专用工具集目录、海量存储的网络资源目录等等。是的,这是一个异常熟悉的领域:在文件系统目录里,我们存储文件及其大小、创建日期、类型等信息;在诸如记事本类的专用工具集目录里,我们存放日程安排、联系方式、人员地点等信息;在网络资源目录里,我们以分层架构存放网络上所有对象的相关资料,这些对象包罗了网络里使用的各种资源:共享目录、共享打印机、应用程序、服务、服务器、用户帐号、组、域…可以这样说,从使用计算机的那一刻起,我们就从未离开过目录!曾经,这样的目录让我们随心所欲地处理我们的资源!

然而,正是这样的目录,在Internet下却面临许多麻烦:种类繁多、数量日增的目录让我们很难准确定位想要的资源;系统目录、应用程序特定目录、网络资源目录中到底谁存储了我们需要的信息?如何能用一致的方式登录这些不同的资源?怎样能轻松地维护不同系统上的远程资源?能否通过可视化的程序界面在这些资源间交互?

初识Active Directory活动目录

要解决这些问题,你可以使用Micrsoft提供的活动目录Active Directory 对象,它提供一种构造复杂计算机网络的简单方法,用来存储公共文件夹、对象信息、打印机、服务等数据;

Active Directory的适用范围很大,它可以用在小自一台计算机,一个计算机网络,大至数个广域网络(WAN)的结合。它可以包含这个范围中所有的对象:文件、打印机、应用程序、服务器、域,以及用户等等。与普通意义上的目录不同的是, Active Directory活动目录以分层树状结构排列成节点树,每个节点表示网络上的一个资源或服务,并且包含一组可检索和操作的属性。Active Directory 是提供复杂网络统一视图的 Windows目录服务,它减少了开发人员必须处理的目录和命名空间的数量。

Directory Service目录服务

同时,专门针对Active Directory活动目录的Directory Services目录服务则让目录中的信息可用,Directory Service(目录服务)是让用户很容易地在目录内寻找到所需要的对象的一种服务。通过对Active Directory中数据的整理、规划存储,目录服务使得目录中的信息可用,真正让目录"活动"起来了。理由很明显,Internet网络、WAN局域网络里海量存储的数据往往让你迷失不知所措,再加上这些存放的资料不加以整理,想找到您需要的资料谈何容易!相反地,如果经过适当的规划,事先有系统地去整理这些资料,那就可以在需要时方便快速地寻找到你所要的对象。这样的例子现实生活中也随处可见:查号台算得上是一种目录服务;在Internet上的搜索引擎提供的查询功能究其实也是一种目录服务。目录服务不仅广义地包括了上述的各种目录(共享目录、共享打印机、应用程序、服务,网络服务器、用户帐号、计算机帐号、域、安全规则等等),更重要的它同时也是一种服务,让管理者、用户及应用程序都能利用目录中的资料处理这些对象。

其实,目录服务早就以不同的形式出现许多应用领域:一些操作系统如Microsoft的NT中的NTDS( Windows NT Directory Service), Novell 中的NDS(Novell Directory Service )等都整和了这种运用;另外,它也常集成在应用程序中,如Microsoft Exchange Server等。

作为Active Directory的广泛应用,Microsoft更是以Active Directory及其Service服务为整个分布式运算环境的基础。它可以包含并管理前述不同操作系统及应用程序相关的各种目录服务,提供用户、管理者,及程序开发者一个通用的目录服务,大大减少了企业的负担。

Active Directory支持的标准——走进ADSI

为实现活动目录服务,Active Directory支持了以下开放的标准: LDAP轻型目录访问协议(Lightweight Directory Access Protocol)是用于访问Acitve Directory中数据的一个标准,它同时又是一个编程接口,提供API用来访问Active Directory活动目录;还有一个专门用于用户身份验证的标准是Kerberos协议,Windows 和Unix均支持这一协议以验证用户身份!

另外,为进一步简化程序方式访问Active Directory,Microsoft专门提供了ADSI(Active

Directory Service Interface)活动目录服务接口语言,更使得编程人员可以更轻松地访问Active Directory的所有功能!使用ADSI,可以创建执行常见管理任务的应用程序,这些任务包括备份数据库、访问打印机和管理用户帐户等。ADSI 使管理员能够相对方便地定位和管理网络上的资源,不管网络的大小如何。

若要使用 ADSI 技术,在客户端计算机上必须提供有ADSI SDK或ADSI运行库,这可以通过安装 ADSI 2.5 或更高版本来实现。对于 Windows NT 5.0 版、Windows 2000 或 Windows

XP,默认安装了 ADSI 2.5。如果使用的是以前版本的 Windows,则您可以自己从

Microsoft Web 站点安装该 SDK。

Active Directory架构

Active Directory架构(Schema)包含定义了各种形式的能够在Active Directory中使用的对象类(如共享打印机、共享目录等),它同时也定义了在Active Directory允许存在的各种属性以提供对象的附加信息,如Name、Guid标识等,这种定义目录对象、属性的方式与数据库架构定义数据库结构的方式大体相同。架构信息存储在 Active Directory 层次结构中,可以大大加快在大型目录上进行成员搜索的速度。Active Directory 使用架构定义可以访问网络节点的指定信息。架构提供了一种给存储在目录中的对象类型创建全局定义的方法,这些定义并赋予有意义的名称,如“用户”和“计算机”,更易于用户的访问识别。

.Net架构支持DirectoryServices名字空间.Net架构对Active Directory提供了丰富的支持功能,其命名空间

oryServices包含的DirctoryEntry、DirectoryEntries以及DirectorySearcher等类库可与任何

Active Directory

服务提供程序(一种识别绑定协议并提供相关服务的程序,下面有专门阐述)一起使用,.NET

框架的这些支持使得操作具有 DirectoryEntry 和 DirectorySearcher

等组件的 ADSI 功能非常容易。DirectoryEntry组件DirectoryEntry

组件使从目录访问对象以及使用其数据和行为非常方便。当给

DirectoryEntry 组件指定一个 Active Directory

层次结构中的有效目录路径时,它返回可操作的 ADSI COM

对象,这些对象包括用户、计算机、服务、用户帐户和计算机的组织、文件系统以及文件服务操作。DirectoryEntry

类封装 Active Directory

层次结构中的节点或对象,使用此类库绑定到对象、读取属性和更新特性。DirectoryEntry

与帮助器类一起为生存期管理和导航方法提供支持,包括创建、删除、重命名、移动子节点和枚举子级。可以将 DirectoryEntry

组件绑定到目录中的对象以执行管理任务,如修改属性或监视信息更改。可以使用 DirectoryEntry

组件自动执行常见管理任务,如添加用户和组、管理打印机以及设置网络资源的权限。这样,你可以使用

DirectoryEntry

组件与企业中任何目录系统上的任何资源进行交互。可以向层次结构添加新的节点。当然,如果需要更改

Active Directory

对象的属性值,你必须拥有所绑定到对象的管理权限。在创建新的对象时,DirectoryEntry 组件会用到 Active Directory Schema

架构。这时你需要指定一个先前已存在的架构名,并将该对象与之关联。DirectorySearcher组件DirectorySearcher 组件使用Active Directory架构信息在目录中执行搜索并获得节点的属性并返回

SearchResult 的实例,这些实例包含在 SearchResultCollection

类的实例中。SearchResult 的实例与 DirectoryEntry

的实例非常类似。明显的差异在于每次访问新对象时,DirectoryEntry

都从 Active Directory 层次结构中检索其信息,而 SearchResult

的数据已经存在于用 DirectorySearcher 执行的查询返回的

SearchResultCollection 中。SearchResult 中只存在那些在查询中通过

tiesToLoad 属性的集合指定的属性。可以使用 DirectorySearcher 类对使用轻量目录访问协议(Lightweight

Directory Access Protocol,LDAP)的 Active Directory

层次结构进行搜索以查找特定的服务或对象;可以基于大型目录中对象的属性

(Rich Query)

执行查询,以便按其一个或多个属性值查找特定的对象;可以封装层次结构中的节点,并操作或查询其属性。DirectorySearcher

组件的实例需要 LDAP 提供程序以便对 Active Directory

层次结构执行多格式查询。LDAP

是系统提供的唯一一种支持搜索的 Active Directory 服务接口 (ADSI)

提供程序。目录服务提供程序可以使用 DirectoryEntry

组件访问的每种目录系统类型都具有一种特定的目录协议(称为“服务提供程序”),此协议允许您访问和处理该目录的内容。创建ADSI可使开发人员通过单个接口访问所有的协议,从而可以方便地在这些协议之间进行切换。下表列出了可以访问的服务提供程序以及每种服务提供程序的标识符服务提供程序路径标识符Windows NT 5.0 版、Windows 2000 或 Windows XP轻量目录访问协议(LDAP)Novell NetWare 目录服务Novell Netware PAT://binderyServer/TopHat每种服务提供程序为您提供一组不同的可访问和操作的对象以及关联数据和行为。这些对象与该命名空间的目录树中的项和资源对应。很多提供程序具有相同的对象。例如,所有提供程序授予您访问组对象(表示一个组帐户)和用户对象(表示一个用户帐户)的权限。对于 Windows NT

服务提供程序,您可以访问域、计算机、打印队列和会话。对于

LDAP 提供程序,您可以访问组织、地址和"根 DS 项"(rootDSE)

对象。LDAP把rootDSE定义为目录服务器中目录树的根。根 DS

项是一组必需的操作属性,用户可以读取这些属性以找出目录和服务器的基本特征:如读取默认命名环境名(default

naming context), rootDSE 仅对 LDAP 提供程序是必需的。绑定及路径当创建DirectoryEntry组件的实例时,需要指定所使用的服务提供程序的类型以及要操作的对象,并与Active

Directory连接,这个过程称为“绑定”。这时,你需要指定所使用的协议(LADP、WinNT等),即服务提供程序指示符。当前的一些服务提供程序包括

Internet 信息服务 (IIS)、轻量目录访问协议 (LDAP)和 WinNT等。随后你可能需要指定计算机所在的域名、组名以及计算机名,如果没有显示式指定域名(服务器名),系统就会在整个域中查找与用户绑定过程相关的域控制器,并且使用所找到的第一个域控制器。这样,WinNT下的绑定语法大致为:://MyDomain/://MyDomain/MyComputer/aPrinter/这个过程中,可能需要指定路径信息,类DirectoryEntry的Path属性唯一地标识网络环境中的路径信息,设置该属性将从目录存储区检索新项,它不更改当前绑定的项的路径。同绑定类似,Path

属性的语法取决于服务提供程序,在WinNT

下连接到计算机上的组语法为:WinNT://domain/computer/group;而IIS下连接到Web目录则为:IIS://LocalHost/W3SVC/1/ROOT/web-directory-name。ADSI可实现的操作依赖于.Net架构类库的强大支持,使用ADSI使以下操作变得简单可行:1、一次登录可处理不同的目录。DirectoryEntry

组件类提供用户名和密码属性,可以在运行时输入这些属性并与绑定到的

Active Directory 对象进行通讯。2、通过给用户提供各种要使用的协议,使用单个应用程序编程接口

(API) 即可在多个目录系统上执行任务。3、对目录系统执行"多格式查询"。ADSI

技术允许通过指定两种查询语言,即 SQL 和 LDAP,来搜索对象。4、通过访问 Active Directory

树,访问和使用用于管理和维护各种复杂网络配置的单个分层结构。5、将目录信息与数据库(如 SQL Server)进行集成。只要

DirectoryEntry 路径使用 LDAP 提供程序,就可以将它用作

连接字符串。实 例运用上面的知识,以下创建了一个Windows Forms程序实例,它可以列出本地计算机上的用户、组和服务。程序实现时,请拖放TreeView控件到窗体上,设置其名为viewPC(它将在程序中提供三个顶级节点,各个节点分别用于用户User、组Group和服务Services。每个二级节点都将代表一个在您的计算机上注册的用户、组或服务。每个用户、组和服务都具有两个子节点,一个用于其

Active Directory 路径Path,另一个用于其属性Porperties);同时,请添加引用。并从组件中拖入

DirectoryEntry 组件,配置 DirectoryEntry 组件属性,设置其名Name

属性为 entryPC。将 DirectoryEntry 组件的 Path 属性设置为 WinNT://研发中心/Webserver。(这里,“研发中心”是笔者所在的组名,“Webserver”则是笔者所使用的计算机服务器名,你可能需要修改它们)。运行程序,就将可视化地列出指定计算机上的所有用户、组和服务,展开这些节点,将罗列出它们各自的路径及属性。主要源代码如下:private void Form1_Load(object sender, rgs e){TreeNode users=new TreeNode("Users");TreeNode groups=new TreeNode("Groups");TreeNode services=new TreeNode("Services");ge(new

TreeNode[]{users,groups,services});

foreach(DirectoryEntry child in en){TreeNode newNode=new TreeNode();switch(ClassName){case "User":(newNode);break;case "Group":(newNode);break;case "Service":(newNode);break;}try{ AddPathAndProperties(newNode,child);} catch(Exception ex)

{(e) }}}//以下函数实现路径及属性的添加功能private void AddPathAndProperties(TreeNode node,DirectoryEntry entry){(new TreeNode("Path:" ));TreeNode propertyNode=new TreeNode("Properties");(propertyNode);foreach(string propertyName in tyNames){String oneNode=propertyName ":" ties[propertyName][0].ToString();(new TreeNode(oneNode));}}程序拓展运行以上程序段将列举出本地机上注册的用户、组、服务及其属性。要列举远程计算机的相应属性,你需要更改DirectoryEntory组件的Path属性为远程计算机名,比如"销售事业部"是笔者所在公司的一个远端工作组,"Xsb1"是这个组中的一台计算机,设置Path=WinNT://销售事业部/Xsb1,就可以列出该机所配置的相关属性。不过,要保证这一功能的实现,你需要确保此远程计算机(如Xsb1)启动了Guest客户访问权限,否则将引发"访问被拒绝"异常;同时,你也需要确保该远程机能支持Active

Directory活动目录,即提供了ADSI SDK运行库,否则,将引发"计算机名无效"异常。运行环境程序在:Windows XP中文操作系统、Microsoft .Net Frameworks框架、Visual

正式中文版下调试通过在本机添加的GUST组中添加用户using System;using c;using ;using Directory;using ols;using ;namespace test14ADControl{class Program{static void Main(string[] args){try{// DirectoryEntry AD = new DirectoryEntry("LDAP://taskin","admin", "battalion");DirectoryEntry AD = new DirectoryEntry("WinNT://" + eName +

",computer");DirectoryEntry NewUser = ("TestUser2", "user");("SetPassword", new object[] { "#12345Abc" });("Put", new object[] { "Description", "Test User from .NET" });Changes();DirectoryEntry grp;grp = ("Guests", "group");if (grp != null){("Add", new object[] { ng() });}ine("Account Created Successfully");ne();}catch (Exception ex){ine(e);ne();}}}}LDAP的请求及处理代码片段using System;using c;using ;using Directory;using ols;using ;namespace test14ADControl{class Program{static void Main(string[] args){NetworkCredential ne = new NetworkCredential("admin", "battalion");LdapConnection ldcon = new LdapConnection("192.168.11.10");tial = ne;();string targetDN = "DC=taskin,DC=com,DC=cn";string ou = "OU=MyOU," + targetDN;string objectClass = "organizationalUnit";///创建AddRequest addrequest = new AddRequest(ou, objectClass);AddResponse addresponse = (AddResponse)quest(addrequest);///删除DeleteRequest deltet = new DeleteRequest(ou);DeleteResponse delresponse = (DeleteResponse)quest(deltet);ine("Account Created Successfully");ne();}}}备注:是.net2.0新增加的一个针对目录服务访问协议处理的组件,其下只有一个ols命名空间。在该命名空间下,主要有LDAP、DSML两种国际标准协议的一系列实现类。通过这些类,完全可以很方便地实现对目录的操作管理用户利用LdapConnection/DsmlSoapHttpConnection跟LDAP服务器/DSML服务器建立连接并绑定后,即可创建一系列相应的操作请求(如增加一新对象请求AddRequest),然后通过连接对象的SendRequest方法把请求命令发送到服务器,服务器根据请求进行相应处理后,把应答信息传回给客户端LDAP资料 AD 编程 2007-06-15 09:20:15 阅读90 评论0 字号:大中小 订阅

理解与应用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、建立“树根”,这是通过修改“”来实现的,由于现在的目的是理解,所以具体步骤就不说了,反正就是在这一步建立了一个“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=orgobjectClass:organizationalPersoncn:stancn:小刀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,使之储存系统用户,这里有一个非常好的网址,如果你的英文不是很差,都应该做的来,我偷个懒,就先不写这方面的东西喽:/en/docs/上面的方法我已经试过,是可行的,如果兄弟们配置的时候出现问题我们可以讨论讨论。关于LDAP+POSTFIX,POSTFIX里的“LDAP_README”中介绍的很详细,我再说就是重复了。##############################################################其它相关资源:yala

(很实用的数据库操作工具,简单的说,他就是MYSQL的phpmyadmin,自己找下载地址吧~)/

(说实话,我一直没用上它,不过它是官方网站,不提也不好)/

(什么‘类’下面有什么‘属性’,在这里找)关于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目录树。(当然要有权限,很危险哦,后果自负,呵呵), 找本书看吧,很简单,和SQL语言其实很类似,易学难精。呵呵。AD组问题A User Group is a logical grouping of user accounts under one entity, theentity(group) represents all users that are included in it as such it can be

granted rights and permissions that all members will under Windows 2000 are classified under two main classes that determine

the groups ability to receive responsibilities (type) and the groups recommended procedure of using groups in a single domain based environmentis:1. Add user accounts to Domain Global groups based on logical groupings(departments, job description ect.).2. Add Domain Global groups to Domain local groups created to representdifferent resources (shares, printers ect.).3. Grant permission to the Domain Local groups.4. In a multi domain environment use Universal groups for problems that can’tbe solved with the former solution such as consolidating multiple Globalgroups from different domains under one group.

需要注意的是:按类型:分为安全组和分布组;按范围:分为全局组、域本地组(Domain Local Group)和通用组。组的类型决定组可以管理哪些类型的任务,组的范围决定组可以作用的范围。1。安全组:顾名思义用户安全设置(授权)方面(每个安全组都有SID),安全组的成员能继承安全组的权限(这一点最重要)2。通讯(分布)组:通讯组不具备安全相关的功能(没有SID),不能用于设置访问控制,通常用于发送电子邮件。注意:安全组具备分布组的功能,你可以理解分布组是安全组的子集。下面按照范围划分的组就要引出混合模式和本机模式了(建议楼主先具备区分两者的概念,可以看看帮助)3。全局组:全局组的范围(指派权限的范围)是整个林(可以把域的资源权限指派给同林其他域的全局组『跨林应该不行』),但是只能内涵本域的帐号和组(本机模式下可以包含同域的其他全局组)。4。域本地组:范围是本域。内含是任何域的用户帐户,任何域的全局组,本机模式下可以包含林内任何域的通用组和同域的域本地组。5。通用组:范围是整个林,内含是任何域的用户帐户,任何域的全局组,任何域的通用组。补充:在计算机加入域前就只有本地组(local group):应用范围是本机(只有本机资源可以指派)。加入域后本地组除了可包含本地用户和内置组外还可以包含同域用户帐户,同域的域本地组,整个林的全局组,通用组。最好设置管理域资源的时候把权限设定在域本地组上(如果直接设定给用户帐号,一旦改帐号将来删除,会带来错误)通常的做法是:把用户组织为全局组,把全局组加入域本地组,把访问权限指派给域本地组。这就是所谓“AGDLP”规则。注意:由于GC中不仅包含通用组,还包含有通用组的成员信息,因此每次对通用的修改(成员增加/删除),都会引发GC复制流量。所以,通用组的成员不要经常频繁的发生变化。否则会带来大量的复制流量。另外,WIN2000在登录时系统需要向GC查询用户的通用组成员身份,以生成访问令牌,所以在GC不可用时,WIN2000用户有可能不能正常访问网络资源。楼主,你没仔细看我写的,或者我写的太乱。1。使用通用组的目的是为了简化管理(减少管理工作量),如果不使用通用组,就要将各个全局组加入到域本地组,最后将权限指派给该组。因为全局组使用范围虽然大,但是其成员只能是本域的。而使用通用组就简化了操作步骤---如有一个新的资源要指派权限。我们只需要把该通用组指派到域本地组就可以了,而不需要把N个全局组添加到域本地组。尤其是资源越分散的林内,优点就越明显。我不是jzlld那样的老师,我暂时想不出形象的例子来说明使用通用组的好处,值得注意的是,在多域环境,分散于多域的多种资源需要指派给分散于多域的多个用户,而该用户具有相似的特征(例如分属各个分公司的同一部门)。这时使用通用组能有效减少管理员的工作量,并保持较“干净”的分组环境(这不是官方的名词),但是有些朋友的DC经常报错,请我去帮忙的时候,我常常会看到剪不断理还乱的分组环境(简单的说是乱分,分到最后很多用户都有莫名其妙的权限),很头痛的。另外,单域单站点的环境下,我们可以使用通用组替代全局组,但是在多域多站点环境下,这样做效率太低。我认为使用全局组的目的是避免频繁修改通用组带来的全局编录复制的负担。2。说明你还没有认真看,在概念上没有理解全局组和通用组的区别。3。加入全局组的目的主要还是简化操作。避免把管理员累死以及保持纯洁。4。二楼哥们写的也是这几种组的概念我刚才找了一下,江小帅过去举过类似的例子,下面我改编了一下。全局组:中国世界贸易部门(中国范围内的全局组)----应用范围是全世界的,单成员不管是单位(组)还是个人(帐户)都是中国的。通用组:国际世界贸易组织----这范围和成员就大了。因为国际世界贸易组织(通用组)地位的重要(小布什觊觎已久),一旦其中发生人事变动就必须要通知到其范围内的所有国家的(全局组)---在各个站点的GC因为要同步开始复制数据会造成网络的负担,一些比较偏远的国家(网络连接不太好,导致数据同步出现问题)可能无法及时发现这些人事变动,就会产生错误“怎么换人了?我还不知道。”当然各个国家的世界贸易部门(全局组)发生人事变动就不用这么大费周章了。如果各个国家想要了解互相鸡蛋市场的价格(分散在各个国家(域)的资源),那么直接问对方要就要对方把权限指派给自己本国的贸易部门(全局组),上百个国家来要就要指派上百次。如果对方是以世贸组织的名义来得,我们只需要指派给世贸组织(通用组)就行了。关你张三李四英国人美国人,只要你是世贸的就可以了。值得注意的是:因为鸡蛋市场上的老板们不认识外国人,这就必须要给外国人一个名义也好介绍信也好,暂时加入中国农村信用合作社(域本地组)吧。本来我在看关于Kerberos的书,因为这也牵涉到组的访问控制及权限继承。所以我才有兴趣回答这方面的问题--当然我也在论坛上搜索了过去的很多帖子。说实话看你的问题像看文字游戏。呵呵,其实你之所以会有这么多问题是因为你还没有真正从概念上理解组的意义。或者说没明白组的好处。建议你动手配置一个环境测试一下各个组之间的关系。立刻就能明白为什么不能乱划分组。我不知道你是准备靠网络认证还是要找工作。我觉得你在问问题上花了太多的时间。网管是一项以实践为基础的工作。他不像哲学,不像数学。单纯的思考不能帮助你有效的理解这些概念。我打赌你动手配置一下几个小时就明白了。与其抱着书本反复思考概念和考试中出题人有可能怎么换个说法来问,不如动动手。你会发现其实这都是简单的概念,不需要死记硬背的。我给你一个例子,你配置一下,两个电脑就行(虚拟机也行)。1。先创建一个简单的林环境:第一个域(林根域)的DC是GC,第二个域的是个标准DC。2。升级为本机模式。3。在每个域中都创建一个通用组。4。分别把两个域的administrator帐号放到对方的这个通用组中。5。在第二个域的DC上我们打开该域administrator帐号的属性,点击成员。我们可以发现在此不会显示其是根域的通用组成员(当前DC不是GC)6。在根域的DC上查看administrator帐号的属性的时候,我们在其成员选项中可以看到他是第二个域通用组成员。(默认根域是GC,你可以用nlterst /dsgetdc:域名

/gc来看看)你可以思考一下,或者你自己按照自己的想法试验一下,看看能不能得出“意外”的结果上面的例子目的还是帮你区分全局组和通用组。这也就是你问的第一个问题和第二个问题的回答。看啊,你两个问题甚至一样长。对于第三个问题,用户加入组和组加入组权限上没什么区别,我不明白“那他的权限与全局组的区别”指的是什么,看你的使用方式,好像域本地组和全局组与通用组的区别并不大。我建议你在使用域本地组和全局组的时候最好表述清楚--哪个域的域本地组?哪个域的全局组?域本地组和全局组成员身份存储在本地域中(这个说法可能不太“官方”),不存储在GC中。通用组存在GC中。看起来似乎差别不大,但是应用起来却差很多。1。因为在分支的DC上执行LDAP(如果你不知道为什么要执行也暂时没关系,你可以想象成为一种检索)只能返回该DC所在域的域本地组和全局组。2。在GC上LDAP能返回GC所在域的域本地组和全局组还有林中的全局组(可以在WIN2003的DC上缓存通用组成员,2000可能不行我没试过)。我建议你不要考虑太多的能与不能。你应该多考虑怎么做好--效率更高,更容易修改,更不容易出错(想想之前说的“AGDLP”规则)。之前我们讨论的都是能与不能的。而且也举了不少例子,概念也是反复前调(可以再看看3楼,基本上3楼的概念也是总结过去的帖子)。举个具体的例子在单域的情况下:一个公司内市场部和行政部的员工需要使用打印机(老板考虑到成本问题要求限制使用打印机),作为网管你把市场部员工帐号加入到A组(全局组----如果将来和总公司域合并了你就明白好处了),把行政部的员工帐号加入B组(全局组);创建一个可以使用该打印机的域本地组C(创建一个域本地组把该打印机的使用权赋予该组);把A,B组都加入到C组。下面来说明一下,如果将来市场部不需要使用该打印机了,只需要把A组从C组里删掉就可以了。如果我们没有设置A组,直接就把市场部成员帐号一个一个加到C组里,那么此时我们要一个一个从里面删除(删到一般领导又后悔的可能性还是有的);如果将来需要市场部所有员工使用另一资源时,我们就不用再创建A组了(节省了工作量);尤其该资源位于另一信任域内时这优点就更加明显(在这里就暂不讨论了)。如果又有新的部门暂时需要使用打印机,我们把他们加入C组就可以---如果C组内不是一个一个的组而是一个一个的帐号,那么将来他们不需要的时候从C组中删除的时候我们就有可能误删市场部和行政部内需要经常使用打印机的帐户,如果使用组就排除了这种可能性(这难道不好吗)。为什么要创建C组呢?想象一下如果没有C组打印机的访问控制列表会有多复杂。直接把权限指派给全局组效率太低。怎么样?现在是不是对于域本地组和全局组的概念清晰很多了?再举一个例子帮助你理解全局组和通用组。如果是在多域的林环境,例如一个大公司的几个分公司范围内每个分公司都是林内不同的域(假设是甲,乙,丙三个域),领导要求三个域的市场部员工都能相互访问对方的市场部业绩报表。我们如果不使用通用组看看会怎么实现。把三个域的市场部设置为三个全局组,把三个全局组的权限分别设置在三个域的报表上(最好也不要直接在报表的ACL上设置全局组,还是把全局组加入域本地组,原因看上面的例子)。如果用通用组,把三个域的市场部设置为全局组,把三个全局组设置为通用组,把三个域的报表上设置相同的权限--给通用组(也是把通用组加入域本地组,原因看上面)。你可以想想哪种更简便。在这个例子里,域越多使用通用组优点越明显。值得注意的是,因为通用组需要在GC上复制,如果通用组的成员变更就需要做数据同步的操作。所以我们把组加入通用组而不是帐户。一旦有人事变更我们只需要修改其所在的全局组就好了。不用管通用组。如果你不想日志里满是莫名其妙的错误就最好避免把本地域资源权限直接指派给别的域的全局组和通用组。尽量把域内权限相同的帐号总结在全局组内,再把全局组加入实现功能的各个域本地组。在多域环境把权限相同的全局组加入通用组。组的嵌套不要太过于复杂,尽管有时候这很难把握。我很希望你看到这里的时候能高兴的说,哇,我完全懂了。 尽管我也知道这不太显示,老实说这难点不在概念上,而在应用上。其实除了这些组之外还有系统的内置组,除了内置的域本地组还有内置全局组,通用组。除此之外还有内置的系统组(Builtin Security Principal)据个例子,论坛里有个老兄面试的时候就遇到过----------“EXCH DOMAIN

SERVERS

EXCH ENTERPRISE SERVERS只见的区别和作用?是否可以移动到其他的容器?”怎么样?这两个组是安装Exchange之后自动产生的。EXCH DOMAIN SERVERS

是全局组,而EXCH ENTERPRISE SERVERS是本地域.而且EXCH DOMAIN SERVERS

属于EXCH ENTERPRISE

是不允许移动这两个组和重命名的。--当然我第一次看到这个问题也吓了一跳,这也是听高手解答的。当然我并不是给了你一个钻牛角尖的方向。你还是理清楚前面的概念吧。有问题你还可以问,有高手愿意指点也欢迎。大家共同进步。说句题外话,如果想搞得很透彻最好还是多看看原理性的书,当然也要多实践。我在看Kerberos这本书之前对KDC,SID,SPN什么票证票据的非常莫名其妙,也奇怪为什么总要认证而且会过期之类,因为在查找微软的KB的时候常常会看到类似的解释,包括各种认证都觉得难以理解。从原理入手就能理解很多东西都是必要的。当然我看的这个书也还是很浅,我也没有足够的精力和智慧深入研究。呵呵。不过学习确实是令人愉快的一件事。其中作者举了一个很生动的例子来演示Kerberos事务处理的过程:一个间谍需要和他的间谍组织联系并交换情报,间谍发出了一个信号,组织决定派一个信使和他见面交换情报,当然间谍和信使互相都不认识他们都只认识组织的头子。以下是他们联系的过程1。信使先联系组织头子,发消息说“告诉一个只有你和那个间谍才知道的秘密”,2。间谍头子为了证明信使的身份是否真实会先验证该消息的真实性,他检验的结果--该消息使用信使的加密密钥(secret eneryption key)来加密的。3。头子给信使回信,这封信分为两个部分:第一部分是一个随机数,他是头子随便决定的并用信使的密钥加密,第二部分包含相同的随机数,信使的姓名,起草信的时间和日期以及信的有效期,这部分用间谍的密钥来加密。4。信使收到头子回信后用自己的密钥成功解出前半部分中的随机数。---当然如果解出的结果是乱码那说明这个头子是假的。信使把信收好去和间谍接头。5。两人见面后互通了姓名,信使把回信的后半部分交给间谍(原作者建议大家去看一下昆汀。塔伦迪诺拍的《水库狗》『Reservir Dogs』)5.1如果间谍用自己的密钥无法对后半部信件解码,他就知道信使是假的,所以开枪射信使。5.2如果能解码但是得到乱码,他就知道信被篡改了,他还会开枪射他。5.3如果能解码但是得到的信使姓名与刚才通报的不同,他依然开枪。5.4如果得到的随机数过去得到过,他还射他,5.5如果得到的有效期过期了,他会扔掉信走掉。6。很幸运没出现上述的情况,间谍会交给信使一封信,其中包含了间谍的姓名,当前时间以及信件中字母总数并用刚才那封信理头子的随机数编码--该随机数成了密钥。7。信使用随机数解码,如果解除不对他就会对间谍开枪。如果时间过期他也会。8。最后信使成功解码,内容可以接受,认证过程结束。两人开始交流情报。当然这个例子是用来理解身份验证的,并不是对Kerberos的解释。我很难找到类似的例子帮助楼主理解组。当然前面也有不错的例子了。剩下的只是动手了。问题描述:AGDLP策略是什么?问题回答:这个实际上就是在域中使用组的策略,它指将域用户的账号(A)添加到全局组(G)中,将全局组添加到域本地组(DL),然后给域本地组分配资源的权限(P)。这种策略提供了比较大的灵活性oryServices 命名空间 AD 编程 2007-06-15 14:13:36 阅读85 评论0 字号:大中小 订阅

oryServices 命名空间用以从托管代码简便地访问 Active Directory。该命名空间包含两个组件类,即 DirectoryEntry 和 DirectorySearcher,它们使用 Active Directory 服务接口 (ADSI) 技术。ADSI 是 Microsoft 提供的一组接口,作为使用各种网络提供程序的灵活的工具。无论网络有多大,ADSI 都可以使管理员能够相对容易地定位和管理网络上的资源。

此命名空间中的类可以与任何 Active Directory 服务提供程序一起使用。当前的一些提供程序包括 Internet 信息服务 (IIS)、轻量目录访问协议 (LDAP)、Novell NetWare 目录服务

(NDS) 和 WinNT。ADSI 是 Microsoft Active Directory 的编程接口,使应用程序能够只使用一个接口就可以与网络上的不同目录进行交互。使用 ADSI,可以创建一些应用程序,用以执行常见任务,如备份数据库、访问打印机和管理用户帐户Active Directory 是一种树结构。树中的每个节点包含一组属性。使用此命名空间可遍历、搜索和修改树,以及读取和写入节点的属性。DirectoryEntry 类封装 Active Directory 层次结构中的节点或对象。使用此类绑定到对象、读取属性和更新特性。DirectoryEntry 与帮助器类一起为生存期管理和导航方法提供支持,包括创建、删除、重命名、移动子节点和枚举子级。DirectoryEntry 类备注使用该类绑定到对象,或读取和更新属性。DirectoryEntry,与帮助器类一起,为生存期管理和导航方法提供支持。这些包括创建、删除、重命名、移动子节点和枚举子级。修改节点之后,必须提交更改,以便将它们保存到树中。可以使用 DirectoryEntry 访问架构项中的常规项和一些(但不是所有)信息。Active Directory 层次结构包含多达数千个节点。每个节点表示一个对象,如网络打印机或域中的用户。公司网络会因为聘用新员工和添加对象(如网络打印机和计算机)而经常发生变化。Active Directory 服务接口 (ADSI) 技术提供了以编程方式向目录树中添加这些对象的途径。若要在层次结构中创建目录项,请使用 Children 属性。Children 属性是一个集合,提供

Add 方法,通过该方法将节点直接添加到当前绑定到的父节点之下的集合。当向集合中添加节点时,必须指定新节点的名称以及要与该节点相关联的架构模板的名称。例如,您可能需要使用标题为“Computer”的架构在层次结构中添加新的计算机。该类还包含属性缓存,这对于优化网络流量十分有用。与 DirectoryEntry 组件关联的类可以与任何 Active Directory 服务提供程序一起使用。当前的一些提供程序包括 Internet 信息服务 (IIS)、轻量目录访问协议 (LDAP)、Novell NetWare

目录服务 (NDS) 和 WinNT。使用 DirectorySearcher 类对 Active Directory 层次结构执行查询。LDAP 是系统提供的唯一一种支持搜索的 Active Directory 服务接口 (ADSI) 提供程序。Active Directory备注使用轻量目录访问协议 (LDAP) 并使用 DirectorySearcher 对象对 Active Directory 层次结构进行搜索和执行查询。LDAP 是系统提供的唯一支持目录搜索的 Active Directory 服务接口

(ADSI) 提供程序。管理员可以创建、更改和删除在层次结构中找到的对象Active Directory编程详解 AD 编程 2007-06-18 10:24:23 阅读57 评论0 字号:大中小 订阅

24.4 Active Directory编程要开发Active Directory程序,必须导入oryServices命名空间。还必须引用oryServices程序集。使用这个程序集中的类可以查询对象、查看和更新属性,搜索对象,把对象移动到其他容器对象中等。在下面的代码段中,简单的C#控制台应用程序说明了如何使用oryServices命名空间中的类。本节将介绍:●

oryServices命名空间中的类● 连接Active Directory的处理方式:绑定● 获取目录项,创建新对象,并更新已有的项目● 搜索Active Directory24.4.1 oryServices命名空间中的类表24-1列出了oryServices命名空间中的主要类。表

24-1类DirectoryEntry说 明这个类是oryServices命名空间中的主类。这个类的对象表示Active Directory库中的一个对象。使用这个类可以绑定对象,查看和更新属性。对象的属性都放在PropertyCollection中。PropertyCollection中的每个元素都有一个PropertyValueCollectionDirectoryEntries是DirectoryEntry对象的一个集合。DirectoryEntry对象的Children属性返回DirectoryEntries集合中DirectoryEntries的一个对象列表DirectorySearcher这个类主要用于用指定的属性搜索对象。要定义该搜索,可以使用SortOption类和枚举SearchScope、SortDirection

ReferalChasingOption。搜索的结果是一个SearchResult或SearchResultCollection。也可以得到ResultPropertyCollection

ResultPropertyValueCollection对象24.4.2

绑定要获得Active Directory中一个对象的值,必须连接Active Directory服务。这个连接过程称为绑定,绑定路径如下所示。LDAP:///OU=Development, DC= AthenaProject, DC=Com在绑定过程中,可以指定下述内容:● 指定提供程序使用的协议(protocol)。● 域控制器的服务器名(server name)。● 服务器过程的端口号(port number)。● 对象的显名(distingunshed name),以标识要访问的对象。● 如果需要访问Active Directory的用户不是运行当前进程的账户,则提供用户名和密码。● 如果需要加密,应指定authentication类型。下面详细介绍这些内容。1. 协议绑定路径的第一部分指定ADSI提供程序。该提供程序是一个COM服务器;prog-id的标识信息在注册表的HKEY_CLASSES_ROOT下。Windows XP附带的提供程序如表24-2所示。2. 服务器名在绑定路径中,服务器名在协议的后面。如果用户登录到Active Directory域上,服务器名就是可选的。如果不提供服务器名,就会发生无服务器绑定操作,此时Windows Server 2003会在域中查找与用户绑定过程相关的、“最好的”域控制器。如果站点中没有服务器,就使用查找到的第一个域控制器。无服务器的绑定如下所示:LDAP://OU=Sales,DC=AthenaProject,DC=Local表

24-2协 议LDAP说 明LDAP服务器,例如Exchange目录和Windows 2000 Server或Windows Server 2003 Active Directory服务器GCGC用于访问Active Directory中的全局目录。它也可以用于快速查询IISWinNT使用IIS的ADSI提供程序,可以在IIS目录中创建和管理新网站要访问旧Windows NT 4域的用户数据库,可以使用WinNT

的ADSI提供程序。NT4用户只有几个属性没有改变。也可以使用这个协议绑定Windows 2000域,但这里也限制了可用于NT4的属性这个progID用于和Novell Directory Services通信使用NWCOMPAT可以访问旧的Novell目录,例如Novell Netware COMPAT3. 端口号在服务器名的后面,可以指定服务器过程的端口号,其语法是:xxx。LDAP服务器的默认端口号是端口389: LDAP://:389。Exchange服务器使用的端口号与LDAP服务器一样。如果在同一个系统上安装了Exchange服务器,例如用作Active Directory的域控制器,就可以配置另一个端口。4. 显名在路径中指定的第四部分是显名(distinguished name,DN)。显名是一个惟一的名称,标识要访问的对象。在Active Directory中,可以使用基于X.500的LDAP语法,指定对象的名称。例如有一个显名:CN=Christian Nagel, OU=Consultants, DC= AthenaProject, DC=local这个显名指定域中域组件(Domain Component,DC) AthenaProject的组织单元(Organizational Unit,OU) Consultants的公共名称(Common Name,CN) Christian

Nagel。最右边的部分是域的根对象。该名称必须符合对象树中的分层方式。显名的字符串表示的LDAP规范在 RFC 2253( /rfc/)上。(1) 相对显名相对显名(RDN)用于引用容器对象中的对象。使用RDN时,不需要指定OU和DC,有一个公共名称就足够了。CN=Christian Nagel就是组织单元中的一个相对显名。如果已经引用了一个容器对象,要访问其子对象,就可以使用相对显名。(2) 默认的命名环境如果在路径中没有指定显名,绑定过程就会使用默认的命名环境(default naming context)。使用rootDSE可以读取默认命名环境。LDAP 3.0把rootDSE定义为目录服务器中目录树的根。例如LDAP://rootDSE

或:LDAP://servername/rootDSE

通过列举rootDSE的所有属性,将获得没有指定名称时可以使用的defaultNamingContext信息。schemaNamingContext 和 configurationNamingContext指定了用于访问模式所需要的名称和Active Directory库中的配置。通过下面的代码可获得rootDSE的所有属性:using (DirectoryEntry de = new DirectoryEntry()){ = "LDAP://platinum/rootDSE";me = @" platinumchristian";rd = "password";PropertyCollection props = ties;foreach (string prop in tyNames){PropertyValueCollection values = props[prop];foreach (string val in values){(prop + ": ");ine(val);}}}这个程序显示了默认的命名环境(defaultNamingContext DC=eichkogelstrasse、 DC=local),用于访问模式的环境(CN=Schema、 CN=Configuration、 DC=eichkogelstrasse、 DC=local)和配置的命名环境(CN=Configuration、 DC=eichkogelstrasse、 DC=local),如图24-9所示。图

24-9(3) 对象标识符每个对象都有一个全局惟一的标识符GUID。GUID是一个惟一的128位数字,您可能已经在COM开发中了解了它。可以使用GUID绑定一个对象。这样,即使对象移动到另一个容器中,也可以得到该对象。GUID在创建对象时生成,且总是保持不变。使用Guid可以得到GUID的字符串表示。这个字符串表示就可以用于绑定对象。下面的示例显示了一个无服务器绑定的路径名称,它绑定到GUID代表的一个特定对象上:LDAP://(4) Windows NT域中的对象名WinNT提供程序不允许在绑定字符串的名称部分使用LDAP语法。在这个提供程序中,对象用ObjectName、ClassName指定。Windows NT域的有效绑定字符串如下:WinNT:WinNT://DomainNameWinNT://DomainName/UserName, userWinNT://DomainName/ServerName/MyGroup, groupuser和group后缀指定可以访问类型为user或group的对象。5. 用户名有时,在访问目录时,必须使用一个非当前进程的用户名(也许这个用户没有访问Active

Directory所必须的许可),此时必须为绑定过程显式指定用户证书(user credential)。Active

Directory提供了许多方式来设置用户名。(1) Downlevel登录使用downlevel登录,用户名可以用Windows 2000以前的域名来指定:domainusername(2) 显名也可以用user对象的显名来指定用户,例如:CN=Administrator,

CN=Users,DC=athenaproject,DC=local(3) User Principal Name (UPN)对象的UPN用userPrincipalName属性来定义。系统管理员可以在Active Directory Users and

Computers工具中User属性的Account选项卡上,用登录信息来指定UPN,注意这不是用户的电子邮件地址。这些信息也惟一地标识了用户,可以用于登录:Nagel@ 6. 身份验证为了给身份验证进行安全的加密,也可以指定身份验证(authentication)类型。身份验证可以用DirectoryEntry类的AuthenticationType属性设置。可以指定其值为AuthenticationTypes枚举中的一个值。因为枚举是用属性[Flags]标识的,所以可以指定多个值。其可能的值有:对发送的数据进行加密的ReadonlyServer,它指定只需要读取访问,Secure表示安全的身份验证。7. 用DirectoryEntry类绑定oryEntry类可以用于指定所有的绑定信息。可以使用默认的构造函数,用Path、Username、Password和 AuthenticationType属性定义绑定信息,或者把这些信息传递给构造函数:DirectoryEntry de = new DirectoryEntry(); = "LDAP://platinum/DC=athenaproject, DC=local";me = "nagel@ ";rd = "password";// use the current user credentialsDirectoryEntry de2 = new DirectoryEntry("LDAP://DC= athenaproject, DC=local");即使成功地构造了DirectoryEntry对象,也并不意味着绑定成功了。在第一次读取属性时进行绑定,可以避免不必要的网络流通量。对象是否存在,或者指定的用户证书是否正确,都可以在第一次访问该对象时确定。24.4.3 获取目录项前面介绍了如何指定Active Directory中对象的绑定属性,下面要读取对象的属性。在下面的示例中要读取用户对象的属性。DirectoryEntry类的一些属性可以提供对象的信息,即Name、Guid和 SchemaClassName属性。第一次访问DirectoryEntry对象的属性时,会执行绑定操作,并填充底层ADSI对象的缓存。后面将详细讨论这些。其他属性可以从缓存中读取,同一对象的数据不需要通过与服务器的通信来获得。在本例中,用组织单元Wrox Press中的公共名称Christian Nagel访问一个用户对象:using (DirectoryEntry de = new DirectoryEntry()){ = "LDAP://platinum/CN=Christian Nagel, " +

"OU=Wrox Press, DC=athenaproject, DC=local";ine("Name: " + );ine("GUID: " + );ine("Type: " + ClassName);ine();//...}Active Directory对象包含许多信息,这些信息取决于对象的类型。属性Properties将返回一个PropertyCollection。每个属性本身就是一个集合,因为一个属性可以有多个值,例如,user对象可以有多个电话号码。在本例中,用一个内部foreach循环查看这些值。从properties[name]返回的集合是一个object数组。属性值可以是字符串、数字或其他类型。使用ToString()方法就可以显示这些值:ine("Properties: ");PropertyCollection properties = ties;foreach (string name in tyNames){foreach (object o in properties[name]){ine(name + ": " + ng());}}在得到的结果中,包含了user对象Christian Nagel的所有属性,如图24-10所示。OtherTelephone是一个多值属性,它包含许多电话号码。一些属性值只显示System._ComObject对象的类型,例如,lastLogoff、lastLogon和nTSecurityDescriptor。要得到这些属性的值,必须直接使用oryServices命名空间的类中的ADSI COM接口。图

24-10注意:第28章介绍了如何使用COM对象和接口。2. 直接通过名称访问属性使用 ties可以访问所有属性。如果已知属性名,就可以直接访问其值:foreach (string homePage in ties["wWWHomePage"])ine("Home page: " + homePage);24.4.4 对象集合对象在Active Directory中是分层存储的。容器对象包含子对象。使用DirectoryEntry类的Children属性可以枚举容器中的子对象。另一方面,使用Parent属性可以得到对象的容器。用户对象没有子对象,所以下面的示例使用一个组织单元,如图24-11所示。非容器对象用Children属性返回一个空集合。下面在域的组织单元Wrox Press中获得其所有的用户对象。Children属性返回一个DirectoryEntries集合,其中包含DirectoryEntry对象。迭代所有的DirectoryEntry对象,显示子对象的名称。using (DirectoryEntry de = new DirectoryEntry()){ = "LDAP://platinum/OU=Wrox Press, " +

"DC=athenaproject, DC=local";ine("Children of " + );foreach (DirectoryEntry obj in en){ine();}}图

24-11本例显示了组织单元中的所有对象:users、contacts、printers、shares和其他组织单元。如果只需要查看某些对象类型,可以使用DirectoryEntries类的SchemaFilter属性。SchemaFilter属性返回一个SchemaNameCollection。有了这个SchemaNameCollection,就可以使用Add()方法定义要查看的对象类型。在本例中,因为只需要查看user对象,所以把user添加到这个集合中:using (DirectoryEntry de = new DirectoryEntry())

{ = "LDAP:// platinum /OU=Wrox Press, " +

"DC= athenaproject, DC=local";ine("Children of " + );("user");foreach (DirectoryEntry obj in en){ine();}}结果,只显示组织单元中的user对象,如图24-12所示。24.4.5 缓存要减少网络流通量,ADSI使用缓存来存储对象属性。如前所述,在创建DirectoryEntry对象时,是不访问服务器的。只要从目录库中读取第一个属性,所有的属性都会写到缓存中,这样,在读取下一个属性时,就不需要往返于服务器了。写入对象的改变,只会改变已缓存的对象。设置属性不会产生网络流通量。必须使用Changes()才能刷新缓存,把所有已改变的数据传送回服务器。要再次从目录库中获取新写入的数据,可以使用hCache()读取属性。当然,如果没有调用CommitChanges() 和RefreshCache()就修改了一些属性,所有的改变都会丢失,因为我们将再次使用RefreshCache()读取目录服务中的值。把属性pertyCache设置为false,就可以关闭这个属性cache。但除非在进行调试,否则最好不要关闭它,因为这会与服务器间产生许多不必要的往返通信。24.4.6 创建新对象创建新Active Directory对象时,例如users、computers、printers和contacts等,可以使用DirectoryEntries类以编程的方式来完成创建工作。要给目录添加新对象,首先必须绑定一个容器对象,例如组织单元,可以在其中插入一个新对象。不包含其他对象的对象是不能使用的。下面使用一个容器对象,其显名为CN=Users,DC= athenaproject,DC=local:DirectoryEntry de = new DirectoryEntry(); = "LDAP://platinum/CN=Users, DC= athenaproject, DC=local";使用DirectoryEntry的Children属性,可以得到一个DirectoryEntries对象:DirectoryEntries users = en;使用DirectoryEntries,可以添加、删除和查找集合中的对象。下面创建一个新的user对象。使用Add()方法时,需要一个对象名和一个类型名。使用ADSI Edit很容易获得类型名:DirectoryEntry user = ("CN=John Doe", "user");对象现在有了默认属性值。要指定特定的属性值,可以使用Properties属性的Add()方法添加属性。当然,所有的属性都必须存在于user对象的模式中。如果指定的属性不存在,就得到一个COMException“指定的目录服务属性或值不存在”:ties["company"].Add("Some Company");ties["department"].Add("Sales");ties["employeeID"].Add("4711");ties["samAccountName"].Add("JDoe");ties["userPrincipalName"].Add("JDoe@ ");ties["givenName"].Add("John");ties["sn"].Add("Doe");ties["userPassword"].Add("someSecret");此时,为了把数据写入Active Directory,必须刷新缓存中的数据:Changes();24.4.7 更新目录项Active Directory服务中对象的更新和读取一样简单。可以在读取对象后修改它们的值。要删除一个属性的所有值,可以调用()方法。使用Add(),可以把新值添加到属性中。Remove()和RemoveAt()可以从属性集合中删除指定的值。要修改一个值,可以把这个值设置为指定的值。下面的代码将通过PropertyValueCollection的一个索引符把移动电话号码设置为一个新值。使用该索引符,只能改变已存在的值。因此,应使用ns()来确定属性是否可用。using (DirectoryEntry de = new DirectoryEntry()){ = "LDAP://platinum /CN=Christian Nagel, " +"OU=Wrox Press, DC= athenaproject, DC=local";if (ns("mobile")){ties["mobile"][0] = "+43(664)3434343434";}else{ties["mobile"].Add("+43(664)3434343434");}Changes();}在本例的else部分,如果移动电话号码不存在新属性,就用方法PropertyValue

()添加它。如果使用Add()方法和已有的属性,得到的结果将取决于属性的类型:单值属性或多值属性。使用Add()方法和已有的单值属性,会得到一个COMException:A constraint violation occurred。使用Add()方法和已有的多值属性则会成功地把另一个值添加到属性中。User对象的属性mobile定义为单值属性,所以不能添加其他移动电话的号码。但是用户可以有多个移动电话的号码。对于多个移动电话的号码,可以使用属性otherMobile,它是一个多值属性,允许设置多个移动电话号码,所以可以调用Add()多次。多值属性有一个重要的检查:即检查其唯一性。如果把第二个电话号码添加到同一个user对象上,也会得到一个COMException:指定的目录服务属性或值已经存在。提示:在创建或更新新的目录对象后,应调用Changes()。否则只能更新缓存中的信息,改变的信息不会发送到目录服务上。24.4.8 访问内部的ADSI对象调用预定义的ADSI接口方法常常比搜索对象的属性名容易得多。一些ADSI对象还支持不能在DirectoryEntry类中直接使用的方法。例如IADsServiceOperations接口有启动和停止Windows服务的方法。Windows服务将在第32章讨论。如本章前面所述,oryServices命名空间的类使用底层的ADSI COM对象。DirectoryEntry支持直接使用Invoke()方法调用底层对象的方法。Invoke()的第一个参数是应在ADSI对象中调用的方法名,第二个参数的params关键字允许把数量可变的其他参数传送给ADSI方法:public object Invoke(string methodName, params object[] args);

在ADSI文档中介绍了可以用Invoke()方法调用的方法。域中的每个对象都支持IADS接口的方法。前面创建的User对象也支持IADsUser接口的方法。在下面的代码示例中,使用方法sword()改变前面创建的user对象的密码:using (DirectoryEntry de = new DirectoryEntry()){ = "LDAP://platinum /CN=John Doe, " +

"CN=Users, DC= athenaproject, DC=local";("SetPassword", "anotherSecret");Changes();}如果不使用Invoke(),还可以直接使用底层的ADSI对象。要使用这些对象,必须使用Project | Add Reference添加对Active DS Type Library的引用,如图24-13所示。这会创建一个包装器类,在该类中可以访问ActiveDS命名空间中的这些对象。图

24-13内部对象可以使用DirectoryEntry类的NativeObject属性来访问。在下面的示例中,对象de是一个user对象,所以可以把它强制转换为er。SetPassword()是在IADsUser接口中说明的方法,所以可以直接调用它,而不是使用Invoke()方法来调用。把IADsUser的AccountDisabled属性设置为false,就可以激活账户。与前面的示例一样,调用CommitChanges() 和DirectoryEntry对象,把改变的内容写到目录服务中:er user = (er)Object;sword("someSecret");tDisabled = false;Changes();24.4.9

在Active Directory中搜索Active Directory是一个数据库,它为大多数读取访问进行了优化,所以一般应使用搜索一些值。要在Active Directory中搜索,可以使用.NET Framework中的类DirectorySearcher。注意:DirectorySearcher只能和LDAP提供程序一起使用。它不能和NDS或IIS提供程序一起使用。在类DirectorySearcher的构造函数中,可以定义搜索的4个重要部分。也可以使用默认构造函数,用属性定义搜索选项。1. SearchRootSearchRoot指定搜索应从什么地方开始。SearchRoot的默认值是当前使用的域的根。SearchRoot用DirectoryEntry对象的Path指定。2. 过滤器过滤器定义了希望有的值。过滤器是一个必须放在括号中的字符串。表达式中可以使用关系运算符,如<=、 =、 >=。(objectClass=contact)会搜索所有类型为contact的对象,(lastName>=Nagel) 会按字母表的顺序搜索lastName属性等于或大于Nagel的所有对象。表达式可以和前缀运算符 & 和 |组合使用。例如,(&(objectClass=user)(description=Auth*))搜索类型为User,其属性description以字符串Auth开头的所有对象。因为 & 和 | 运算符在表达式的开头,所以可以把多个表达式用一个前缀运算符组合在一起。默认过滤器是(objectClass=*),所以将选择所有的对象。注意:过滤器语法在RFC 2254中定义为“LDAP搜索过滤器的字符串表示”。这个RFC在/rfc/中。3. PropertiesToLoad使用PropertiesToLoad,可以定义所有属性的StringCollection。对象可以有许多属性,其中的大多数对于搜索请求都不太重要。我们定义了应加载到缓存中的属性。如果没有指定属性,默认属性就应是对象的Path 和Name属性。4. SearchScopeSearchScope 是一个枚举,定义了搜索应延伸的深度:●

只搜索对象中的属性,至多可以得到一个对象。●

el表示在基对象的子集合中继续搜索。基对象本身是不搜索的。●

e定义了在整个树中搜索。SearchScope属性的默认值是e。5. 搜索的限制在目录服务中搜索特定的对象可以在几个域中进行。对搜索要限制对象的个数或搜索时间,可以定义其他几个属性(如表24-3所示)。表 24-3属 性ClientTimeout说 明客户机等待服务器返回结果的最长时间。如果服务器没有响应,就不返回记录使用

paged search,服务器会返回用PageSize

定义的许多对象,而不是所有的对象。这会减少客户获得第一个答案的时间和需要的内存,服务器把一个cookie送给客户机,客户机再把下一个搜索请求发送回服务器,这样搜索就可以在上一次结PageSize束的地方继续进行ServerPageTimeLimit对于paged search,这个值定义了一个搜索时间,在该时间内返回用PageSize

值定义的许多对象。如果这段时间在PageSize值之前到达,就会把此时查找到的对象返回给客户机。默认值为-1,表示时间为无限定义服务器搜索对象的最长时间。过了这段时间后,就会把此时查找到的所有对象返回给客户机。默认值是120秒,不能把搜索时间设置为较高的值搜索可以在几个域中进行。如果用SearchRoot

指定的根是一个父域或没有指定根,就会继续在子域中搜索。使用这个属性可以指定是否应在不同的服务器上继续搜索表示不能在不同的服务器上继续搜索inate指定继续在子域中搜索,搜索ServerTimeLimitReferalChasing从DC=Wrox、DC=COM开始时,服务器可以返回一个结果集,例如DC=France、DC=Wrox、DC=COM引用。客户机可以继续在子域中搜索al表示服务器可以让客户机搜索不在子域中的另一个服务器,这是默认选项表示返回外部和从属的引用在搜索示例中,要搜索组织单元Wrox Press中description属性值为Author的所有user 对象。首先,绑定组织单元Wrox Press,在该组织单元中开始搜索。创建一个DirectorySearcher对象,在其中设置SearchRoot。过滤器定义为(&(objectClass=user) (description=Auth*)),这样就可以搜索所有类型为User、description属性以Auth开头的对象。搜索的范围应在一个子树中,即在Wrox Press的子组织单元中搜索:using (DirectoryEntry de =

new DirectoryEntry("LDAP://OU=Wrox Press, DC= athenaproject, DC=local"))using (DirectorySearcher searcher = new DirectorySearcher()){

Root = de; = "(&(objectClass=user)(description=Auth*))";Scope = e;要在搜索结果中包含的属性有name、description、givenName和WWWHomePage。("name");("description");("givenName");("wWWHomePage");下面准备开始搜索。还应对结果进行排序。DirectorySearcher有一个属性Sort,它可以设置SortOption。SortOption构造函数的第一个参数定义了要排序的属性,第二个参数定义了排序的方向。SortDirection枚举的值是Ascending 和 Descending。要开始搜索,可以使用FindOne()方法查找第一个对象,或者使用FindAll()。FindOne()返回一个简单的SearchResult,FindAll()返回一个SearchResultCollection。要得到所有的作者对象,就应使用FindAll(): = new SortOption("givenName", ing);SearchResultCollection results = l();使用一个foreach循环,可以访问SearchResultCollection中的每个SearchResult。一个SearchResult表示搜索缓存中的一个对象。Properties属性返回一个ResultPropertyCollection,使用属性名和索引符可以访问该集合中所有的属性:SearchResultCollection results = l();foreach (SearchResult result in results){ResultPropertyCollection props = ties;foreach (string propName in tyNames){(propName + ": ");ine(props[propName][0]);

}ine();}}可以在搜索之后获得完整的对象:SearchResult有一个方法GetDirectoryEntry(),它返回查找到的对象的相应DirectoryEntry。得到的结果应显示《Professional C#》(即《C#高级编程》)的作者列表,这些作者都有我们指定的属性,如图24-14所示。24.5

搜索用户对象本章的最后一节要创建一个Windows Forms应用程序UserSearch。这个应用程序是非常灵活的,因为可以输入特定的域控制器、用户名和密码,以访问Active Directory,或者使用运行进程的用户。在这个应用程序中,我们将访问Active Directory服务的模式,获得user对象的属性。该用户可以输入一个过滤器字符串,搜索域中的所有user对象。还可以设置应显示的user对象的属性。24.5.1 用户界面用户界面显示了一些已编好序号的步骤,说明如何使用该应用程序(如图24-15所示):图

24-15● 在第一步中,输入用户名、密码和域控制器。所有这些信息都是可选的。如果没有输入域控制器,就要使用无服务器绑定进行连接。如果没有输入用户名,就使用当前用户的安全环境。● 使用一个按钮,就可以把User对象的所有属性名动态加载到listBoxProperties

列表 框中。● 在加载了属性名后,就可以选择要显示的属性。列表框的SelectionMode设置为MultiSimple。● 可以输入限制搜索的过滤器,在该对话框中设置的默认值是搜索所有的user对象:(objectClass=user)。● 现在开始搜索。24.5.2 获取模式命名环境这个应用程序只有两个处理程序方法:按钮的第一个处理程序方法加载属性,第二个处理程序方法则在域中开始搜索操作。在第一部分,从模式中动态读取User类的属性,在用户界面中显示它。在处理程序方法buttonLoadProperties_Click()中,使用SetLogonInformation()从对话框中读取用户名、密码和主机名,并存储在类的成员中。接着,SetNamingContext()方法设置模式的LDAP名称和默认环境的LDAP名称。这个模式LDAP名称用于调用中,以设置列表框中的属性SetUserProperties()。private void buttonLoadProperties_Click(object sender, rgs e){try{SetLogonInformation();SetNamingContext();SetUserProperties(schemaNamingContext);}catch (Exception ex){("Check your inputs! " + e);}}protected void SetLogonInformation(){username = ( == ""password = ( == ""hostname = ;if (hostname != "") hostname += "/";}在帮助方法SetNamingContext()中,使用目录树的根来获得服务器的属性。这里只考虑两个属性的值:schemaNamingContext 和 defaultNamingContext。protected string SetNamingContext(){using (DirectoryEntry de = new DirectoryEntry()){string path = "LDAP://" + hostname + "rootDSE";me = username;rd = password; = path;schemaNamingContext = ties["schemaNamingContext"][0].ToString();defaultNamingContext =

ties["defaultNamingContext"][0].ToString();}}24.5.3 获取User类的属性名使用LDAP名称可以访问模式。使用它可以访问目录,并读取属性。我们不仅要介绍User类的属性,还将介绍User的基类:Organizational-Person、Person和Top。在这个程序中,基类的名称是硬编码的。还可以使用subClassOf属性动态读取基类。GetSchemaProperties()返回一个字符串数组和指定对象类型的所有属性名。这些属性名都在StringCollection属性中:protected void SetUserProperties(string schemaNamingContext){StringCollection properties = new StringCollection();string[] data = GetSchemaProperties(schemaNamingContext, "User");ge(GetSchemaProperties(schemaNamingContext,

"Organizational-Person"));ge(GetSchemaProperties(schemaNamingContext, "Person"));ge(GetSchemaProperties(schemaNamingContext, "Top"));();foreach (string s in properties){(s);}}在GetSchemaProperties()中,再次访问Active Directory服务。这次不使用rootDSE,而使用前面介绍的模式的LDAP名称。属性systemMayContain包含objectType类中的所有属性的一个集合:protected string[] GetSchemaProperties(string schemaNamingContext,

string objectType){string[] data;using (DirectoryEntry de = new DirectoryEntry()){me = username;rd = password; = "LDAP://" + hostname + "CN=" + objectType + "," +

schemaNamingContext;tyCollection properties = ties;tyValueCollection values = properties["systemMayContain"];data = new String[];(data, 0);}return data;}注意上述代码中的tyCollection,这是因为在Windows Forms应用程序中,oryServices命名空间中的PropertyCollection类与tyCollection的名称相冲突。为了避免使用像tyCollection这么长的名称,可以使用下面的代码来缩短命名空间的名称:using DS = oryServices;这样就完成了应用程序的第二步。Listbox控件包含User对象的所有属性名。24.5.4 搜索用户对象搜索按钮的处理程序只调用帮助方法FillResult();private void buttonSearch_Click(object sender, rgs e){try{FillResult();}catch (Exception ex){("Check your input: " + e);}}在FillResult()中,在整个Active Directory 域中进行与前面一样的正常搜索。SearchScope设置为Subtree, Filter设置为TextBox中的字符串,应加载到缓存中的属性由用户在列表框中选择的值来设置。方法GetProperties()用于把属性数组传送给方法searcher。PropertiesTo

ge()是一个帮助方法,它从列表框中把选中的属性度到一个数组中。在设置了DirectorySearcher对象的属性后,就调用SearchAll()方法搜索属性。SearchResultCollection中的搜索结果用于生成写到文本框textBoxResults中的汇总信息。protected void FillResult(){using (DirectoryEntry root = new DirectoryEntry()){me = username;rd = password; = "LDAP://" + hostname + defaultNamingContext;using (DirectorySearcher searcher = new DirectorySearcher()){Root = root;Scope = e; = ;ge(GetProperties());SearchResultCollection results = l();StringBuilder summary = new StringBuilder();foreach (SearchResult result in results){foreach (string propName in

tyNames){foreach (string s in ties[propName]){(" " + propName + ": " + s + "rn");}}("rn");} = ng();}}}启动该应用程序,将列出所有由过滤器选择的有效对象,如图24-16所示。24.6

小结本章介绍了Active Directory的体系结构,有关域、树和森林的重要概念。利用它,我们可以访问整个企业的信息。在编写访问Active Directory服务的应用程序时,必须注意读取的数据可能不是最新的,因为进行复制操作时有一定的等待时间。使用oryServices命名空间中的类,可以很容易地访问封装到ADSI提供程序中的Active Directory服务。DirectoryEntry类可以直接读写数据库中的对象。使用DirectorySearcher类可以进行复杂的搜索,定义过滤器、超时、加载的属性和范围等。使用全局目录,可以加快对整个企业中的对象的搜索,因为它在森林中存储了所有对象的只读版本。

2023年6月21日发(作者:)

Microsoft LDAP 错误代码Microsoft Windows 2000 Active Directory 使用 Internet 标准的轻量级目录访问协议 (LDAP)

来访问信息。在响应各种 LDAP 请求时,域控制器会返回包含域 LDAP 错误代码的响应,这些错误代码指示协议操作的状态。本文将介绍这些错误代码。下表描述了这些错误代码。

代码 值 说明---------------------------------------------------------------------------LDAP_SUCCESS 0x00 请求成功。Sucessful _OPERATIONS_ERROR 0x01 LDAP 库初始化失败。Intialization of

LDAP library _PROTOCOL_ERROR 0x02 出现协议错误。Protocol error _TIMELIMIT_EXCEEDED 0x03 超出时间限制。Time limit has _SIZELIMIT_EXCEEDED 0x04 超出大小限制。Size limit has _COMPARE_FALSE 0x05 比较结果为 FALSE。Compare yielded _COMPARE_TRUE 0x06 比较结果为 TRUE。Compare yielded _AUTH_METHOD_NOT_SUPPORTED 0x07 不支持此身份验证方法。The

authentication method is not _STRONG_AUTH_REQUIRED 0x08 需要加强的身份验证。Strong authentication is

_REFERRAL_V2 0x09 LDAP 版本 2 检索。LDAP version 2 _PARTIAL_RESULTS 0x09 接收到部分结果和检索。Partial results and referrals _REFERRAL 0x0a 出现检索。Referral _ADMIN_LIMIT_EXCEEDED 0x0b 超出服务器上的管理限制。Administration limit on

the server has _UNAVAILABLE_CRIT_EXTENSION 0x0c 没有精密扩展。Critical extension is

_CONFIDENTIALITY_REQUIRED 0x0d 需要保密。Confidentiality is _NO_SUCH_ATTRIBUTE 0x10 请求的属性不存在。Requested attribute does not _UNDEFINED_TYPE 0x11 类型未定义。The type is not _INAPPROPRIATE_MATCHING 0x12 出现不适当的匹配。 An inappropriate matching

_CONSTRAINT_VIOLATION 0x13 出现约束冲突。A constraint violation _ATTRIBUTE_OR_VALUE_EXISTS 0x14 属性已存在或已被赋值。The attribute exists

or the value has been _INVALID_SYNTAX 0x15 语法无效。The syntax is _NO_SUCH_OBJECT 0x20 对象不存在。Object does not _ALIAS_PROBLEM 0x21 别名无效。The alias is _INVALID_DN_SYNTAX 0x22 辨别名的语法无效。The distinguished name has an

invalid _IS_LEAF 0x23 该对象为叶对象。The object is a _ALIAS_DEREF_PROBLEM 0x24 无法取消对别名的引用。Cannot de-reference the

_INAPPROPRIATE_AUTH 0x30 身份验证不正确。Authentication is _INVALID_CREDENTIALS 0x31 提供的凭据无效。The supplied credential is _INSUFFICIENT_RIGHTS 0x32 用户无足够的访问权限。The user has insufficient access

_BUSY 0x33 服务器忙。The server is _UNAVAILABLE 0x34 服务器不可用。The server is _UNWILLING_TO_PERFORM 0x35 服务器不处理目录请求。The server does not handle

directory _LOOP_DETECT 0x36 引用链循环回至引用服务器。The chain of referrals has looped

back to a referring _NAMING_VIOLATION 0x40 存在命名冲突。There was a naming _OBJECT_CLASS_VIOLATION 0x41 存在对象类别冲突。There was an object class

_NOT_ALLOWED_ON_NONLEAF 0x42 不允许在非叶对象上操作。Operation is not

allowed on a non-leaf _NOT_ALLOWED_ON_RDN 0x43 不允许在 RDN 上操作。Operation is not allowed on

_ALREADY_EXISTS 0x44 对象已存在。The object already _NO_OBJECT_CLASS_MODS 0x45 无法修改对象类别。Cannot modify object _RESULTS_TOO_LARGE 0x46 返回的结果太大。Results returned are too _AFFECTS_MULTIPLE_DSAS 0x47 多个目录服务代理受到影响。Multiple directory

service agents are _OTHER 0x50 出现未知错误。Unknown error _SERVER_DOWN 0x51 无法联系 LDAP 服务器。Cannot contact the LDAP _LOCAL_ERROR 0x52 出现本地错误。Local error _ENCODING_ERROR 0x53 出现编码错误。Encoding error _DECODING_ERROR 0x54 出现解码错误。Decoding error _TIMEOUT 0x55 搜索超时。The search was timed _AUTH_UNKNOWN 0x56 出现未知的身份验证错误。Unknown authentication error

_FILTER_ERROR 0x57 搜索筛选器不正确。The search filter is _USER_CANCELLED 0x58 用户已取消操作。The user has canceled the _PARAM_ERROR 0x59 传递给例程的参数不正确。An incorrect parameter was passed to

a _NO_MEMORY 0x5a 系统内存不足。The system is out of _CONNECT_ERROR 0x5b 无法建立到服务器的连接。Cannot establish a connection to

the _NOT_SUPPORTED 0x5c 不支持此功能。The feature is not _CONTROL_NOT_FOUND 0x5d ldap 函数找不到指定控件。The ldap function did not

find the specified _NO_RESULTS_RETURNED 0x5e 不支持此功能。The feature is not _MORE_RESULTS_TO_RETURN 0x5f 将返回其他结果。Additional results are to be

_CLIENT_LOOP 0x60 检测到客户循环。Client loop was _REFERRAL_LIMIT_EXCEEDED 0x61 超出检索限制。The referral limit was _SASL_BIND_IN_PROGRESS 0x0E 多阶段绑定的中间绑定结果 Intermediary bind

result for multi-stage

完------------------------------------------------------------LDAP介绍1. LDAP介绍 41.1. LDAP是什么 41.2. LDAP是电话簿 41.3. LDAP是不是数据库 42. LDAP的特点 52.1. LDAP的优势 52.1.1 跨平台 52.1.2 费用及维护 52.1.3 复制技术 52.1.4 允许使用ACI 52.2. LDAP存储什么数据 62.3. 什么时候该用LDAP存储数据 63. LDAP的基本模型 73.1 信息模型:描述LDAP的信息表示方式 73.2 命名模型:描述LDAP中的数据如何组织 73.3 功能模型:描述LDAP中的数据操作访问 73.4 安全模型:描述LDAP中的安全机制 83.4.1 身份认证 83.4.2 通讯安全 83.4.3 访问控制 84. LDAP数据结构 94.1 树状组织 94.2 条目和条目认证 94.3 数据样式(schema) 94.4 对象类型(objectClass) 94.5 过滤器和语法 104.6 树移植 104.7 LDIF交换文件 104.8 JAVA或CORBA对象串行化存储 101.1. LDAP是什么LDAP是轻量目录访问协议,英文全称是Lightweight Directory Access Protocol,一般都简称为LDAP。它是基于X.500标准的,但是简单多了并且可以根据需要定制。与X.500不同,LDAP支持TCP/IP,这对访问Internet是必须的。LDAP的核心规范在RFC中都有定义,所有与LDAP相关的RFC都可以在LDAPman RFC网页中找到。简单说来,LDAP是一个得到关于人或者资源的集中、静态数据的快速方式。

LDAP是一个用来发布目录信息到许多不同资源的协议。通常它都作为一个集中的地址本使用,不过根据组织者的需要,它可以做得更加强大。

1.2. LDAP是电话簿LDAP其实是一电话簿,类似于我们所使用诸如NIS(Network Information Service)、DNS

(Domain Name Service)等网络目录,也类似于你在花园中所看到的树木。

1.3. LDAP是不是数据库不少LDAP开发人员喜欢把LDAP与关系数据库相比,认为是另一种的存贮方式,然后在读性能上进行比较。实际上,这种对比的基础是错误的。LDAP和关系数据库是两种不同层次的概念,后者是存贮方式(同一层次如网格数据库,对象数据库),前者是存贮模式和访问协议。LDAP是一个比关系数据库抽象层次更高的存贮概念,与关系数据库的查询语言SQL属同一级别。LDAP最基本的形式是一个连接数据库的标准方式。该数据库为读查询作了优化。因此它可以很快地得到查询结果,不过在其它方面,例如更新,就慢得多。从另一个意义上 LDAP是实现了指定的数据结构的存贮,它是一种特殊的数据库。但是LDAP和一般的数据库不同,明白这一点是很重要的。 LDAP对查询进行了优化,与写性能相比LDAP的读性能要优秀很多。就象Sybase、Oracle、Informix或Microsoft的数据库管理系统(DBMS)是用于处理查询和更新关系型数据库那样,LDAP服务器也是用来处理查询和更新LDAP目录的。换句话来说LDAP目录也是一种类型的数据库,但不是关系型数据库。要特别注意的是,LDAP通常作为一个hierarchal数据库使用,而不是一个关系数据库。因此,它的结构用树来表示比用表格好。正因为这样,就不能用SQL语句了。

2. LDAP的特点2.1. LDAP的优势2.1.1 跨平台LDAP最大的优势是:可以在任何计算机平台上,用很容易获得的而且数目不断增加的LDAP的客户端程序访问LDAP目录。而且也很容易定制应用程序为它加上LDAP的支持。LDAP协议是跨平台的和标准的协议,因此应用程序就不用为LDAP目录放在什么样的服务器上操心了。实际上,LDAP得到了业界的广泛认可,因为它是Internet的标准。产商都很愿意在产品中加入对LDAP的支持,因为他们根本不用考虑另一端(客户端或服务端)是怎么样的。LDAP服务器可以是任何一个开发源代码或商用的LDAP目录服务器(或者还可能是具有LDAP界面的关系型数据库),因为可以用同样的协议、客户端连接软件包和查询命令与LDAP服务器进行交互。与LDAP不同的是,如果软件产商想在软件产品中集成对DBMS的支持,那么通常都要对每一个数据库服务器单独定制。2.1.2 费用及维护不象很多商用的关系型数据库,你不必为LDAP的每一个客户端连接或许可协议付费。大多数的LDAP服务器安装起来很简单,也容易维护和优化。2.1.3 复制技术LDAP服务器可以用"推"或"拉"的方法复制部分或全部数据,例如:可以把数据"推"到远程的办公室,以增加数据的安全性。复制技术是内置在LDAP服务器中的而且很容易配置。如果要在DBMS中使用相同的复制功能,数据库产商就会要你支付额外的费用,而且也很难管理。2.1.4 允许使用ACILDAP允许你根据需要使用ACI(一般都称为ACL或者访问控制列表)控制对数据读和写的权限。例如,设备管理员可以有权改变员工的工作地点和办公室号码,但是不允许改变记录中其它的域。ACI可以根据谁访问数据、访问什么数据、数据存在什么地方以及其它对数据进行访问控制。因为这些都是由LDAP目录服务器完成的,所以不用担心在客户端的应用程序上是否要进行安全检查。2.2. LDAP存储什么数据LDAP对于这样存储这样的信息最为有用:也就是数据需要从不同的地点读取,但是不需要经常更新。例如,这些信息存储在LDAP目录中是十分有效的:l 公司员工的电话号码簿和组织结构图l 客户的联系信息l 计算机管理需要的信息,包括NIS映射、email假名,等等l 软件包的配置信息l 公用证书和安全密匙2.3. 什么时候该用LDAP存储数据大多数的LDAP服务器都为读密集型的操作进行专门的优化。因此,当从LDAP服务器中读取数据的时候会比从专门为OLTP优化的关系型数据库中读取数据快一个数量级。也是因为专门为读的性能进行优化,大多数的LDAP目录服务器并不适合存储需要需要经常改变的数据。例如,用LDAP服务器来存储电话号码是一个很好的选择,但是它不能作为电子商务站点的数据库服务器。如果下面每一个问题的答案都是"是",那么把数据存在LDAP中就是一个好主意。l 需要在任何平台上都能读取数据吗?l 每一个单独的记录项是不是每一天都只有很少的改变?l 可以把数据存在平面数据库(flat database)而不是关系型数据库中吗?换句话来说,也就是不管什么范式不范式的,把所有东西都存在一个记录中(差不多只要满足第一范式)。最后一个问题可能会唬住一些人,其实用平面数据库去存储一些关系型的数据也是很一般的。例如,一条公司员工的记录就可以包含经理的登录名。用LDAP来存储这类信息是很方便的。一个简单的判断方法:如果可以把保数据存在一张张的卡片里,就可以很容易地把它存在LDAP目录里。3. LDAP的基本模型

3.1 信息模型:描述LDAP的信息表示方式

在LDAP中信息以树状方式组织,在树状信息中的基本数据单元是条目,而每个条目由属性构成,属性中存储有属性值;LDAP中的信息模式,类似于面向对象的概念,在LDAP中每个条目必须属于某个或多个对象类(Object Class),每个Object Class由多个属性类型组成,每个属性类型有所对应的语法和匹配规则;对象类和属性类型的定义均可以使用继承的概念。每个条目创建时,必须定义所属的对象类,必须提供对象类中的必选属性类型的属性值,在LDAP中一个属性类型可以对应多个值。

在LDAP中把对象类、属性类型、语法和匹配规则统称为Schema,在LDAP中有许多系统对象类、属性类型、语法和匹配规则,这些系统Schema在LDAP标准中进行了规定,同时不同的应用领域也定义了自己的Schema,同时用户在应用时,也可以根据需要自定义Schema。这有些类似于XML,除了XML标准中的XML定义外,每个行业都有自己标准的DTD或DOM定义,用户也可以自扩展;也如同XML,在LDAP中也鼓励用户尽量使用标准的Schema,以增强信息的互联互通。

在Schema中最难理解的是匹配规则,这是LDAP中为了加快查询的速度,针对不同的数据类型,可以提供不同的匹配方法,如针对字符串类型的相等、模糊、大于小于均提供自己的匹配规则。

3.2 命名模型:描述LDAP中的数据如何组织

LDAP中的命名模型,也即LDAP中的条目定位方式。在LDAP中每个条目均有自己的DN和RDN。DN是该条目在整个树中的唯一名称标识,RDN是条目在父节点下的唯一名称标识,如同文件系统中,带路径的文件名就是DN,文件名就是RDN。

3.3 功能模型:描述LDAP中的数据操作访问

在LDAP中共有四类10种操作:查询类操作,如搜索、比较;更新类操作,如添加条目、删除条目、修改条目、修改条目名;认证类操作,如绑定、解绑定;其它操作,如放弃和扩展操作。除了扩展操作,另外9种是LDAP的标准操作;扩展操作是LDAP中为了增加新的功能,提供的一种标准的扩展框架,当前已经成为LDAP标准的扩展操作,有修改密码和StartTLS扩展,在新的RFC标准和草案中正在增加一些新的扩展操作,不同的LDAP厂商也均定义了自己的扩展操作。

3.4 安全模型:描述LDAP中的安全机制

LDAP中的安全模型主要通过身份认证、安全通道和访问控制来实现。

3.4.1 身份认证在LDAP中提供三种认证机制,即匿名、基本认证和SASL(Simple Authentication and

Secure Layer)认证。匿名认证即不对用户进行认证,该方法仅对完全公开的方式适用;基本认证均是通过用户名和密码进行身份识别,又分为简单密码和摘要密码认证;SASL认证即LDAP提供的在SSL和TLS安全通道基础上进行的身份认证,包括数字证书的认证。

3.4.2 通讯安全在LDAP中提供了基于SSL/TLS的通讯安全保障。SSL/TLS是基于PKI信息安全技术,是目前Internet上广泛采用的安全服务。LDAP通过StartTLS方式启动TLS服务,可以提供通讯中的数据保密性、完整性保护;通过强制客户端证书认证的TLS服务,同时可以实现对客户端身份和服务器端身份的双向验证。

3.4.3 访问控制虽然LDAP目前并无访问控制的标准,但从一些草案中或是事实上LDAP产品的访问控制情况,我们不难看出:LDAP访问控制异常的灵活和丰富,在LDAP中是基于访问控制策略语句来实现访问控制的,这不同于现有的关系型数据库系统和应用系统,它是通过基于访问控制列表来实现的,无论是基于组模式或角色模式,都摆脱不了这种限制。

在使用关系型数据库系统开发应用时,往往是通过几个固定的数据库用户名访问数据库。对于应用系统本身的访问控制,通常是需要建立专门的用户表,在应用系统内开发针对不同用户的访问控制授权代码,这样一旦访问控制策略变更时,往往需要代码进行变更。总之一句话,关系型数据库的应用中用户数据管理和数据库访问标识是分离的,复杂的数据访问控制需要通过应用来实现。

而对于LDAP,用户数据管理和访问标识是一体的,应用不需要关心访问控制的实现。这是由于在LDAP中的访问控制语句是基于策略语句来实现的,无论是访问控制的数据对象,还是访问控制的主体对象,均是与这些对象在树中的位置和对象本身的数据特征相关。

在LDAP中,可以把整个目录、目录的子树、制定条目、特定条目属性集或符合某过滤条件的条目作为控制对象进行授权;可以把特定用户、属于特定组或所有目录用户作为授权主体进行授权;最后,还可以定义对特定位置(例如IP地址或DNS名称)的访问权。

4. LDAP数据结构LDAP是实现了指定的数据结构的存贮,它包括以下可以用关系数据库实现的结构要求:树状组织、条目认证、类型定义、许可树形记录拷贝。4.1 树状组织无论是X500还是LDAP都是采用树状方式进行记录。每一个树目录都有一个树根的入口条目,子记录全部是这一根条目的子孙。这是目录与关系数据类型最大的区别(关系数据库的应用结构也可实现树状记录)。因此,把目录看作是更高级的树状数据库也未尝不可,只不过除此外,它不能实现关系存贮的重要功能。4.2 条目和条目认证LDAP是以条目作为认证的根据。ROOT的权限认证与目录本身无关,但除此外所有条目的认证权限由条目本身的密码进行认证。LDAP可以配置成各种各样不同的父子条目权限继承方式。每一个条目相当于一个单一的平面文本记录,由条目自身或指定的条目认证进行访问控制。因此,LDAP定义的存贮结构等同于一批树状组织的平面数据库,并提供相应的访问控制。条目中的记录以名-值对的形式存在,每一个名值对必须由数据样式schema预定义。因此,LDAP可以看作是以规定的值类型以名值对形式存贮在一系列以树状组织的平面数据库的记录的集合。4.3 数据样式(schema)数据样式schema是针对不同的应用,由用户指定(设计)类和属性类型预定义,条目中的类(objectclass)和属性必须在在LDAP服务器启动时载入内存的schema已有定义。因此,AD活动目录中的条目记录就必须符合Active Directory的schema中。如果已提供的schema中的定义不够用,用户可以自行定义新的schema.在/ 中可以看到常用的schema。4.4 对象类型(objectClass)因为LDAP目录可以定制成存储任何文本或二进制数据,到底存什么要由你自己决定。LDAP目录用对象类型(objectclass)的概念来定义运行哪一类的对象使用什么属性。在几乎所有的LDAP服务器中,你都要根据自己的需要扩展基本的LDAP目录的功能,创建新的对象类型或者扩展现存的对象类型。条目中的记录通过objectclass实现分类,objectClass是一个继承性的类定义,每一个类定义指定必须具备的属性。如某一条目指定必须符合某个类型,则它必须具备超类所指定的属性。通过objectclass分类,分散的条目中的记录就实际上建立了一个索引结构,为高速的读查询打下了基础。Objectclass也是过滤器的主要查询对象。4.5 过滤器和语法LDAP是一个查询为主的记录结构,无论是何种查询方式,最终都由过滤器缺点查询的条件。过滤器相当于SQL中的WHERE子句。任何LDAP的类过滤和字符串都必须放在括号内,如(objectclass=*),指列出所有类型的记录(不过分类)。可以使用=,>=,<=,~=(约等于)进行比较,如(number<=100)。合并条件是最怪的,必须把操作符放在两个操作对象的前面而不是中间,单一操作对象用括号括起来。如l A与B,不是A&B,而是(&(A)(B))。l 或使用"|"表示;l 非使用"!"表示。l 对于"与",或"或"在操作符后可以跟多个条件表达式,但非后则只参是单个表达式。详见RFC1558。4.6 树移植LDAP最重要的特性和要求并不是读性能,而是扩展性。这一特性是通过树移植和树复制实现的。按LDAP的RFC要求,LDAP目录应该可以任意地在不同的目录间连接、合并并实现自动复制,及自动性同步。这意味着用户可以在任一LDAP中访问条目,而不用管其中某一部分是否复制自全世界另一目录中的记录,同时另一目录中的记录同样在正常运作。这一特性如果在关系数据库中实现,意味着要使用程序化的非规范化预复制。类似于汇总帐目的设计。4.7 LDIF交换文件LDIF是LDAP约定的记录交换格式,以平面文本的形式存在,是大部分LDAP内容交换的基础,如拷贝、添加、修改等操作,都是基于LDIF文件进行操作。4.8 JAVA或CORBA对象串行化存储网络高效率的访问加上JAVA的跨平台能力,当把JAVA或CORBA对象串行化后存储到LDAP目录上时,可以产生非同一般的集成效果--实际上,这正是EJB和.NET的网络定位基础技术。使用JAVA或CORBA对象存储时,必须首先让LDAP服务支持该对象定义,也就是说包含或。JAVA必须存储在objectclass=javacontainer的条目中,而且必须带有cn属性,这意味着除非该JAVA类专门实现了DirContext接口,对于大多数JAVA类来说,只能采用DirContext代替Context实现bind的添加操作。取出JAVA类相对要简单得多,只需使用()获得该对象的句柄,然后强制造型成所需要的对象就可以了,如:Person p=(Person)("cn=elvis,dc=daifu,dc=com");这个句法在EJB的程序中,是经常用到的。使用CORBA的跨语言性质,使用CORBA存储对象比JAVA更加诱人,这意味着所存储的对象可以被任何语言编写的客户端访问。其实,微软的.net说到底也非常简单,无非是把COM对象存储到微软自家的目录ActiveDirectory里面,从而可以在网络范围内使用任何微软平台的语言进行对象访问而已。众所周知,COM就是与CORBA相对的微软规范。使用对象串行化技术,可以把常用对象如某个打印机,某个客户直接存储到LDAP中,然后快速获取该对象的引用,这样,就比把对象信息存储到关系数据库中,分别取出属性,然后再初始化对象操作的做法,效率要高得多了。这是LDAP目前比普通关系数据库存储要优秀的地方,而对象数据库还不成熟NET下ActiveDirectory编程技术普通目录及其面临的困难 谈到计算机目录及其相关技术,总能让我们想到无时不在使用的文件系统目录、灵巧实用的专用工具集目录、海量存储的网络资源目录等等。是的,这是一个异常熟悉的领域:在文件系统目录里,我们存储文件及其大小、创建日期、类型等信息;在诸如记事本类的专用工具集目录里,我们存放日程安排、联系方式、人员地点等信息;在网络资源目录里,我们以分层架构存放网络上所有对象的相关资料,这些对象包罗了网络里使用的各种资源:共享目录、共享打印机、应用程序、服务、服务器、用户帐号、组、域…可以这样说,从使用计算机的那一刻起,我们就从未离开过目录!曾经,这样的目录让我们随心所欲地处理我们的资源!

然而,正是这样的目录,在Internet下却面临许多麻烦:种类繁多、数量日增的目录让我们很难准确定位想要的资源;系统目录、应用程序特定目录、网络资源目录中到底谁存储了我们需要的信息?如何能用一致的方式登录这些不同的资源?怎样能轻松地维护不同系统上的远程资源?能否通过可视化的程序界面在这些资源间交互?

初识Active Directory活动目录

要解决这些问题,你可以使用Micrsoft提供的活动目录Active Directory 对象,它提供一种构造复杂计算机网络的简单方法,用来存储公共文件夹、对象信息、打印机、服务等数据;

Active Directory的适用范围很大,它可以用在小自一台计算机,一个计算机网络,大至数个广域网络(WAN)的结合。它可以包含这个范围中所有的对象:文件、打印机、应用程序、服务器、域,以及用户等等。与普通意义上的目录不同的是, Active Directory活动目录以分层树状结构排列成节点树,每个节点表示网络上的一个资源或服务,并且包含一组可检索和操作的属性。Active Directory 是提供复杂网络统一视图的 Windows目录服务,它减少了开发人员必须处理的目录和命名空间的数量。

Directory Service目录服务

同时,专门针对Active Directory活动目录的Directory Services目录服务则让目录中的信息可用,Directory Service(目录服务)是让用户很容易地在目录内寻找到所需要的对象的一种服务。通过对Active Directory中数据的整理、规划存储,目录服务使得目录中的信息可用,真正让目录"活动"起来了。理由很明显,Internet网络、WAN局域网络里海量存储的数据往往让你迷失不知所措,再加上这些存放的资料不加以整理,想找到您需要的资料谈何容易!相反地,如果经过适当的规划,事先有系统地去整理这些资料,那就可以在需要时方便快速地寻找到你所要的对象。这样的例子现实生活中也随处可见:查号台算得上是一种目录服务;在Internet上的搜索引擎提供的查询功能究其实也是一种目录服务。目录服务不仅广义地包括了上述的各种目录(共享目录、共享打印机、应用程序、服务,网络服务器、用户帐号、计算机帐号、域、安全规则等等),更重要的它同时也是一种服务,让管理者、用户及应用程序都能利用目录中的资料处理这些对象。

其实,目录服务早就以不同的形式出现许多应用领域:一些操作系统如Microsoft的NT中的NTDS( Windows NT Directory Service), Novell 中的NDS(Novell Directory Service )等都整和了这种运用;另外,它也常集成在应用程序中,如Microsoft Exchange Server等。

作为Active Directory的广泛应用,Microsoft更是以Active Directory及其Service服务为整个分布式运算环境的基础。它可以包含并管理前述不同操作系统及应用程序相关的各种目录服务,提供用户、管理者,及程序开发者一个通用的目录服务,大大减少了企业的负担。

Active Directory支持的标准——走进ADSI

为实现活动目录服务,Active Directory支持了以下开放的标准: LDAP轻型目录访问协议(Lightweight Directory Access Protocol)是用于访问Acitve Directory中数据的一个标准,它同时又是一个编程接口,提供API用来访问Active Directory活动目录;还有一个专门用于用户身份验证的标准是Kerberos协议,Windows 和Unix均支持这一协议以验证用户身份!

另外,为进一步简化程序方式访问Active Directory,Microsoft专门提供了ADSI(Active

Directory Service Interface)活动目录服务接口语言,更使得编程人员可以更轻松地访问Active Directory的所有功能!使用ADSI,可以创建执行常见管理任务的应用程序,这些任务包括备份数据库、访问打印机和管理用户帐户等。ADSI 使管理员能够相对方便地定位和管理网络上的资源,不管网络的大小如何。

若要使用 ADSI 技术,在客户端计算机上必须提供有ADSI SDK或ADSI运行库,这可以通过安装 ADSI 2.5 或更高版本来实现。对于 Windows NT 5.0 版、Windows 2000 或 Windows

XP,默认安装了 ADSI 2.5。如果使用的是以前版本的 Windows,则您可以自己从

Microsoft Web 站点安装该 SDK。

Active Directory架构

Active Directory架构(Schema)包含定义了各种形式的能够在Active Directory中使用的对象类(如共享打印机、共享目录等),它同时也定义了在Active Directory允许存在的各种属性以提供对象的附加信息,如Name、Guid标识等,这种定义目录对象、属性的方式与数据库架构定义数据库结构的方式大体相同。架构信息存储在 Active Directory 层次结构中,可以大大加快在大型目录上进行成员搜索的速度。Active Directory 使用架构定义可以访问网络节点的指定信息。架构提供了一种给存储在目录中的对象类型创建全局定义的方法,这些定义并赋予有意义的名称,如“用户”和“计算机”,更易于用户的访问识别。

.Net架构支持DirectoryServices名字空间.Net架构对Active Directory提供了丰富的支持功能,其命名空间

oryServices包含的DirctoryEntry、DirectoryEntries以及DirectorySearcher等类库可与任何

Active Directory

服务提供程序(一种识别绑定协议并提供相关服务的程序,下面有专门阐述)一起使用,.NET

框架的这些支持使得操作具有 DirectoryEntry 和 DirectorySearcher

等组件的 ADSI 功能非常容易。DirectoryEntry组件DirectoryEntry

组件使从目录访问对象以及使用其数据和行为非常方便。当给

DirectoryEntry 组件指定一个 Active Directory

层次结构中的有效目录路径时,它返回可操作的 ADSI COM

对象,这些对象包括用户、计算机、服务、用户帐户和计算机的组织、文件系统以及文件服务操作。DirectoryEntry

类封装 Active Directory

层次结构中的节点或对象,使用此类库绑定到对象、读取属性和更新特性。DirectoryEntry

与帮助器类一起为生存期管理和导航方法提供支持,包括创建、删除、重命名、移动子节点和枚举子级。可以将 DirectoryEntry

组件绑定到目录中的对象以执行管理任务,如修改属性或监视信息更改。可以使用 DirectoryEntry

组件自动执行常见管理任务,如添加用户和组、管理打印机以及设置网络资源的权限。这样,你可以使用

DirectoryEntry

组件与企业中任何目录系统上的任何资源进行交互。可以向层次结构添加新的节点。当然,如果需要更改

Active Directory

对象的属性值,你必须拥有所绑定到对象的管理权限。在创建新的对象时,DirectoryEntry 组件会用到 Active Directory Schema

架构。这时你需要指定一个先前已存在的架构名,并将该对象与之关联。DirectorySearcher组件DirectorySearcher 组件使用Active Directory架构信息在目录中执行搜索并获得节点的属性并返回

SearchResult 的实例,这些实例包含在 SearchResultCollection

类的实例中。SearchResult 的实例与 DirectoryEntry

的实例非常类似。明显的差异在于每次访问新对象时,DirectoryEntry

都从 Active Directory 层次结构中检索其信息,而 SearchResult

的数据已经存在于用 DirectorySearcher 执行的查询返回的

SearchResultCollection 中。SearchResult 中只存在那些在查询中通过

tiesToLoad 属性的集合指定的属性。可以使用 DirectorySearcher 类对使用轻量目录访问协议(Lightweight

Directory Access Protocol,LDAP)的 Active Directory

层次结构进行搜索以查找特定的服务或对象;可以基于大型目录中对象的属性

(Rich Query)

执行查询,以便按其一个或多个属性值查找特定的对象;可以封装层次结构中的节点,并操作或查询其属性。DirectorySearcher

组件的实例需要 LDAP 提供程序以便对 Active Directory

层次结构执行多格式查询。LDAP

是系统提供的唯一一种支持搜索的 Active Directory 服务接口 (ADSI)

提供程序。目录服务提供程序可以使用 DirectoryEntry

组件访问的每种目录系统类型都具有一种特定的目录协议(称为“服务提供程序”),此协议允许您访问和处理该目录的内容。创建ADSI可使开发人员通过单个接口访问所有的协议,从而可以方便地在这些协议之间进行切换。下表列出了可以访问的服务提供程序以及每种服务提供程序的标识符服务提供程序路径标识符Windows NT 5.0 版、Windows 2000 或 Windows XP轻量目录访问协议(LDAP)Novell NetWare 目录服务Novell Netware PAT://binderyServer/TopHat每种服务提供程序为您提供一组不同的可访问和操作的对象以及关联数据和行为。这些对象与该命名空间的目录树中的项和资源对应。很多提供程序具有相同的对象。例如,所有提供程序授予您访问组对象(表示一个组帐户)和用户对象(表示一个用户帐户)的权限。对于 Windows NT

服务提供程序,您可以访问域、计算机、打印队列和会话。对于

LDAP 提供程序,您可以访问组织、地址和"根 DS 项"(rootDSE)

对象。LDAP把rootDSE定义为目录服务器中目录树的根。根 DS

项是一组必需的操作属性,用户可以读取这些属性以找出目录和服务器的基本特征:如读取默认命名环境名(default

naming context), rootDSE 仅对 LDAP 提供程序是必需的。绑定及路径当创建DirectoryEntry组件的实例时,需要指定所使用的服务提供程序的类型以及要操作的对象,并与Active

Directory连接,这个过程称为“绑定”。这时,你需要指定所使用的协议(LADP、WinNT等),即服务提供程序指示符。当前的一些服务提供程序包括

Internet 信息服务 (IIS)、轻量目录访问协议 (LDAP)和 WinNT等。随后你可能需要指定计算机所在的域名、组名以及计算机名,如果没有显示式指定域名(服务器名),系统就会在整个域中查找与用户绑定过程相关的域控制器,并且使用所找到的第一个域控制器。这样,WinNT下的绑定语法大致为:://MyDomain/://MyDomain/MyComputer/aPrinter/这个过程中,可能需要指定路径信息,类DirectoryEntry的Path属性唯一地标识网络环境中的路径信息,设置该属性将从目录存储区检索新项,它不更改当前绑定的项的路径。同绑定类似,Path

属性的语法取决于服务提供程序,在WinNT

下连接到计算机上的组语法为:WinNT://domain/computer/group;而IIS下连接到Web目录则为:IIS://LocalHost/W3SVC/1/ROOT/web-directory-name。ADSI可实现的操作依赖于.Net架构类库的强大支持,使用ADSI使以下操作变得简单可行:1、一次登录可处理不同的目录。DirectoryEntry

组件类提供用户名和密码属性,可以在运行时输入这些属性并与绑定到的

Active Directory 对象进行通讯。2、通过给用户提供各种要使用的协议,使用单个应用程序编程接口

(API) 即可在多个目录系统上执行任务。3、对目录系统执行"多格式查询"。ADSI

技术允许通过指定两种查询语言,即 SQL 和 LDAP,来搜索对象。4、通过访问 Active Directory

树,访问和使用用于管理和维护各种复杂网络配置的单个分层结构。5、将目录信息与数据库(如 SQL Server)进行集成。只要

DirectoryEntry 路径使用 LDAP 提供程序,就可以将它用作

连接字符串。实 例运用上面的知识,以下创建了一个Windows Forms程序实例,它可以列出本地计算机上的用户、组和服务。程序实现时,请拖放TreeView控件到窗体上,设置其名为viewPC(它将在程序中提供三个顶级节点,各个节点分别用于用户User、组Group和服务Services。每个二级节点都将代表一个在您的计算机上注册的用户、组或服务。每个用户、组和服务都具有两个子节点,一个用于其

Active Directory 路径Path,另一个用于其属性Porperties);同时,请添加引用。并从组件中拖入

DirectoryEntry 组件,配置 DirectoryEntry 组件属性,设置其名Name

属性为 entryPC。将 DirectoryEntry 组件的 Path 属性设置为 WinNT://研发中心/Webserver。(这里,“研发中心”是笔者所在的组名,“Webserver”则是笔者所使用的计算机服务器名,你可能需要修改它们)。运行程序,就将可视化地列出指定计算机上的所有用户、组和服务,展开这些节点,将罗列出它们各自的路径及属性。主要源代码如下:private void Form1_Load(object sender, rgs e){TreeNode users=new TreeNode("Users");TreeNode groups=new TreeNode("Groups");TreeNode services=new TreeNode("Services");ge(new

TreeNode[]{users,groups,services});

foreach(DirectoryEntry child in en){TreeNode newNode=new TreeNode();switch(ClassName){case "User":(newNode);break;case "Group":(newNode);break;case "Service":(newNode);break;}try{ AddPathAndProperties(newNode,child);} catch(Exception ex)

{(e) }}}//以下函数实现路径及属性的添加功能private void AddPathAndProperties(TreeNode node,DirectoryEntry entry){(new TreeNode("Path:" ));TreeNode propertyNode=new TreeNode("Properties");(propertyNode);foreach(string propertyName in tyNames){String oneNode=propertyName ":" ties[propertyName][0].ToString();(new TreeNode(oneNode));}}程序拓展运行以上程序段将列举出本地机上注册的用户、组、服务及其属性。要列举远程计算机的相应属性,你需要更改DirectoryEntory组件的Path属性为远程计算机名,比如"销售事业部"是笔者所在公司的一个远端工作组,"Xsb1"是这个组中的一台计算机,设置Path=WinNT://销售事业部/Xsb1,就可以列出该机所配置的相关属性。不过,要保证这一功能的实现,你需要确保此远程计算机(如Xsb1)启动了Guest客户访问权限,否则将引发"访问被拒绝"异常;同时,你也需要确保该远程机能支持Active

Directory活动目录,即提供了ADSI SDK运行库,否则,将引发"计算机名无效"异常。运行环境程序在:Windows XP中文操作系统、Microsoft .Net Frameworks框架、Visual

正式中文版下调试通过在本机添加的GUST组中添加用户using System;using c;using ;using Directory;using ols;using ;namespace test14ADControl{class Program{static void Main(string[] args){try{// DirectoryEntry AD = new DirectoryEntry("LDAP://taskin","admin", "battalion");DirectoryEntry AD = new DirectoryEntry("WinNT://" + eName +

",computer");DirectoryEntry NewUser = ("TestUser2", "user");("SetPassword", new object[] { "#12345Abc" });("Put", new object[] { "Description", "Test User from .NET" });Changes();DirectoryEntry grp;grp = ("Guests", "group");if (grp != null){("Add", new object[] { ng() });}ine("Account Created Successfully");ne();}catch (Exception ex){ine(e);ne();}}}}LDAP的请求及处理代码片段using System;using c;using ;using Directory;using ols;using ;namespace test14ADControl{class Program{static void Main(string[] args){NetworkCredential ne = new NetworkCredential("admin", "battalion");LdapConnection ldcon = new LdapConnection("192.168.11.10");tial = ne;();string targetDN = "DC=taskin,DC=com,DC=cn";string ou = "OU=MyOU," + targetDN;string objectClass = "organizationalUnit";///创建AddRequest addrequest = new AddRequest(ou, objectClass);AddResponse addresponse = (AddResponse)quest(addrequest);///删除DeleteRequest deltet = new DeleteRequest(ou);DeleteResponse delresponse = (DeleteResponse)quest(deltet);ine("Account Created Successfully");ne();}}}备注:是.net2.0新增加的一个针对目录服务访问协议处理的组件,其下只有一个ols命名空间。在该命名空间下,主要有LDAP、DSML两种国际标准协议的一系列实现类。通过这些类,完全可以很方便地实现对目录的操作管理用户利用LdapConnection/DsmlSoapHttpConnection跟LDAP服务器/DSML服务器建立连接并绑定后,即可创建一系列相应的操作请求(如增加一新对象请求AddRequest),然后通过连接对象的SendRequest方法把请求命令发送到服务器,服务器根据请求进行相应处理后,把应答信息传回给客户端LDAP资料 AD 编程 2007-06-15 09:20:15 阅读90 评论0 字号:大中小 订阅

理解与应用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、建立“树根”,这是通过修改“”来实现的,由于现在的目的是理解,所以具体步骤就不说了,反正就是在这一步建立了一个“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=orgobjectClass:organizationalPersoncn:stancn:小刀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,使之储存系统用户,这里有一个非常好的网址,如果你的英文不是很差,都应该做的来,我偷个懒,就先不写这方面的东西喽:/en/docs/上面的方法我已经试过,是可行的,如果兄弟们配置的时候出现问题我们可以讨论讨论。关于LDAP+POSTFIX,POSTFIX里的“LDAP_README”中介绍的很详细,我再说就是重复了。##############################################################其它相关资源:yala

(很实用的数据库操作工具,简单的说,他就是MYSQL的phpmyadmin,自己找下载地址吧~)/

(说实话,我一直没用上它,不过它是官方网站,不提也不好)/

(什么‘类’下面有什么‘属性’,在这里找)关于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目录树。(当然要有权限,很危险哦,后果自负,呵呵), 找本书看吧,很简单,和SQL语言其实很类似,易学难精。呵呵。AD组问题A User Group is a logical grouping of user accounts under one entity, theentity(group) represents all users that are included in it as such it can be

granted rights and permissions that all members will under Windows 2000 are classified under two main classes that determine

the groups ability to receive responsibilities (type) and the groups recommended procedure of using groups in a single domain based environmentis:1. Add user accounts to Domain Global groups based on logical groupings(departments, job description ect.).2. Add Domain Global groups to Domain local groups created to representdifferent resources (shares, printers ect.).3. Grant permission to the Domain Local groups.4. In a multi domain environment use Universal groups for problems that can’tbe solved with the former solution such as consolidating multiple Globalgroups from different domains under one group.

需要注意的是:按类型:分为安全组和分布组;按范围:分为全局组、域本地组(Domain Local Group)和通用组。组的类型决定组可以管理哪些类型的任务,组的范围决定组可以作用的范围。1。安全组:顾名思义用户安全设置(授权)方面(每个安全组都有SID),安全组的成员能继承安全组的权限(这一点最重要)2。通讯(分布)组:通讯组不具备安全相关的功能(没有SID),不能用于设置访问控制,通常用于发送电子邮件。注意:安全组具备分布组的功能,你可以理解分布组是安全组的子集。下面按照范围划分的组就要引出混合模式和本机模式了(建议楼主先具备区分两者的概念,可以看看帮助)3。全局组:全局组的范围(指派权限的范围)是整个林(可以把域的资源权限指派给同林其他域的全局组『跨林应该不行』),但是只能内涵本域的帐号和组(本机模式下可以包含同域的其他全局组)。4。域本地组:范围是本域。内含是任何域的用户帐户,任何域的全局组,本机模式下可以包含林内任何域的通用组和同域的域本地组。5。通用组:范围是整个林,内含是任何域的用户帐户,任何域的全局组,任何域的通用组。补充:在计算机加入域前就只有本地组(local group):应用范围是本机(只有本机资源可以指派)。加入域后本地组除了可包含本地用户和内置组外还可以包含同域用户帐户,同域的域本地组,整个林的全局组,通用组。最好设置管理域资源的时候把权限设定在域本地组上(如果直接设定给用户帐号,一旦改帐号将来删除,会带来错误)通常的做法是:把用户组织为全局组,把全局组加入域本地组,把访问权限指派给域本地组。这就是所谓“AGDLP”规则。注意:由于GC中不仅包含通用组,还包含有通用组的成员信息,因此每次对通用的修改(成员增加/删除),都会引发GC复制流量。所以,通用组的成员不要经常频繁的发生变化。否则会带来大量的复制流量。另外,WIN2000在登录时系统需要向GC查询用户的通用组成员身份,以生成访问令牌,所以在GC不可用时,WIN2000用户有可能不能正常访问网络资源。楼主,你没仔细看我写的,或者我写的太乱。1。使用通用组的目的是为了简化管理(减少管理工作量),如果不使用通用组,就要将各个全局组加入到域本地组,最后将权限指派给该组。因为全局组使用范围虽然大,但是其成员只能是本域的。而使用通用组就简化了操作步骤---如有一个新的资源要指派权限。我们只需要把该通用组指派到域本地组就可以了,而不需要把N个全局组添加到域本地组。尤其是资源越分散的林内,优点就越明显。我不是jzlld那样的老师,我暂时想不出形象的例子来说明使用通用组的好处,值得注意的是,在多域环境,分散于多域的多种资源需要指派给分散于多域的多个用户,而该用户具有相似的特征(例如分属各个分公司的同一部门)。这时使用通用组能有效减少管理员的工作量,并保持较“干净”的分组环境(这不是官方的名词),但是有些朋友的DC经常报错,请我去帮忙的时候,我常常会看到剪不断理还乱的分组环境(简单的说是乱分,分到最后很多用户都有莫名其妙的权限),很头痛的。另外,单域单站点的环境下,我们可以使用通用组替代全局组,但是在多域多站点环境下,这样做效率太低。我认为使用全局组的目的是避免频繁修改通用组带来的全局编录复制的负担。2。说明你还没有认真看,在概念上没有理解全局组和通用组的区别。3。加入全局组的目的主要还是简化操作。避免把管理员累死以及保持纯洁。4。二楼哥们写的也是这几种组的概念我刚才找了一下,江小帅过去举过类似的例子,下面我改编了一下。全局组:中国世界贸易部门(中国范围内的全局组)----应用范围是全世界的,单成员不管是单位(组)还是个人(帐户)都是中国的。通用组:国际世界贸易组织----这范围和成员就大了。因为国际世界贸易组织(通用组)地位的重要(小布什觊觎已久),一旦其中发生人事变动就必须要通知到其范围内的所有国家的(全局组)---在各个站点的GC因为要同步开始复制数据会造成网络的负担,一些比较偏远的国家(网络连接不太好,导致数据同步出现问题)可能无法及时发现这些人事变动,就会产生错误“怎么换人了?我还不知道。”当然各个国家的世界贸易部门(全局组)发生人事变动就不用这么大费周章了。如果各个国家想要了解互相鸡蛋市场的价格(分散在各个国家(域)的资源),那么直接问对方要就要对方把权限指派给自己本国的贸易部门(全局组),上百个国家来要就要指派上百次。如果对方是以世贸组织的名义来得,我们只需要指派给世贸组织(通用组)就行了。关你张三李四英国人美国人,只要你是世贸的就可以了。值得注意的是:因为鸡蛋市场上的老板们不认识外国人,这就必须要给外国人一个名义也好介绍信也好,暂时加入中国农村信用合作社(域本地组)吧。本来我在看关于Kerberos的书,因为这也牵涉到组的访问控制及权限继承。所以我才有兴趣回答这方面的问题--当然我也在论坛上搜索了过去的很多帖子。说实话看你的问题像看文字游戏。呵呵,其实你之所以会有这么多问题是因为你还没有真正从概念上理解组的意义。或者说没明白组的好处。建议你动手配置一个环境测试一下各个组之间的关系。立刻就能明白为什么不能乱划分组。我不知道你是准备靠网络认证还是要找工作。我觉得你在问问题上花了太多的时间。网管是一项以实践为基础的工作。他不像哲学,不像数学。单纯的思考不能帮助你有效的理解这些概念。我打赌你动手配置一下几个小时就明白了。与其抱着书本反复思考概念和考试中出题人有可能怎么换个说法来问,不如动动手。你会发现其实这都是简单的概念,不需要死记硬背的。我给你一个例子,你配置一下,两个电脑就行(虚拟机也行)。1。先创建一个简单的林环境:第一个域(林根域)的DC是GC,第二个域的是个标准DC。2。升级为本机模式。3。在每个域中都创建一个通用组。4。分别把两个域的administrator帐号放到对方的这个通用组中。5。在第二个域的DC上我们打开该域administrator帐号的属性,点击成员。我们可以发现在此不会显示其是根域的通用组成员(当前DC不是GC)6。在根域的DC上查看administrator帐号的属性的时候,我们在其成员选项中可以看到他是第二个域通用组成员。(默认根域是GC,你可以用nlterst /dsgetdc:域名

/gc来看看)你可以思考一下,或者你自己按照自己的想法试验一下,看看能不能得出“意外”的结果上面的例子目的还是帮你区分全局组和通用组。这也就是你问的第一个问题和第二个问题的回答。看啊,你两个问题甚至一样长。对于第三个问题,用户加入组和组加入组权限上没什么区别,我不明白“那他的权限与全局组的区别”指的是什么,看你的使用方式,好像域本地组和全局组与通用组的区别并不大。我建议你在使用域本地组和全局组的时候最好表述清楚--哪个域的域本地组?哪个域的全局组?域本地组和全局组成员身份存储在本地域中(这个说法可能不太“官方”),不存储在GC中。通用组存在GC中。看起来似乎差别不大,但是应用起来却差很多。1。因为在分支的DC上执行LDAP(如果你不知道为什么要执行也暂时没关系,你可以想象成为一种检索)只能返回该DC所在域的域本地组和全局组。2。在GC上LDAP能返回GC所在域的域本地组和全局组还有林中的全局组(可以在WIN2003的DC上缓存通用组成员,2000可能不行我没试过)。我建议你不要考虑太多的能与不能。你应该多考虑怎么做好--效率更高,更容易修改,更不容易出错(想想之前说的“AGDLP”规则)。之前我们讨论的都是能与不能的。而且也举了不少例子,概念也是反复前调(可以再看看3楼,基本上3楼的概念也是总结过去的帖子)。举个具体的例子在单域的情况下:一个公司内市场部和行政部的员工需要使用打印机(老板考虑到成本问题要求限制使用打印机),作为网管你把市场部员工帐号加入到A组(全局组----如果将来和总公司域合并了你就明白好处了),把行政部的员工帐号加入B组(全局组);创建一个可以使用该打印机的域本地组C(创建一个域本地组把该打印机的使用权赋予该组);把A,B组都加入到C组。下面来说明一下,如果将来市场部不需要使用该打印机了,只需要把A组从C组里删掉就可以了。如果我们没有设置A组,直接就把市场部成员帐号一个一个加到C组里,那么此时我们要一个一个从里面删除(删到一般领导又后悔的可能性还是有的);如果将来需要市场部所有员工使用另一资源时,我们就不用再创建A组了(节省了工作量);尤其该资源位于另一信任域内时这优点就更加明显(在这里就暂不讨论了)。如果又有新的部门暂时需要使用打印机,我们把他们加入C组就可以---如果C组内不是一个一个的组而是一个一个的帐号,那么将来他们不需要的时候从C组中删除的时候我们就有可能误删市场部和行政部内需要经常使用打印机的帐户,如果使用组就排除了这种可能性(这难道不好吗)。为什么要创建C组呢?想象一下如果没有C组打印机的访问控制列表会有多复杂。直接把权限指派给全局组效率太低。怎么样?现在是不是对于域本地组和全局组的概念清晰很多了?再举一个例子帮助你理解全局组和通用组。如果是在多域的林环境,例如一个大公司的几个分公司范围内每个分公司都是林内不同的域(假设是甲,乙,丙三个域),领导要求三个域的市场部员工都能相互访问对方的市场部业绩报表。我们如果不使用通用组看看会怎么实现。把三个域的市场部设置为三个全局组,把三个全局组的权限分别设置在三个域的报表上(最好也不要直接在报表的ACL上设置全局组,还是把全局组加入域本地组,原因看上面的例子)。如果用通用组,把三个域的市场部设置为全局组,把三个全局组设置为通用组,把三个域的报表上设置相同的权限--给通用组(也是把通用组加入域本地组,原因看上面)。你可以想想哪种更简便。在这个例子里,域越多使用通用组优点越明显。值得注意的是,因为通用组需要在GC上复制,如果通用组的成员变更就需要做数据同步的操作。所以我们把组加入通用组而不是帐户。一旦有人事变更我们只需要修改其所在的全局组就好了。不用管通用组。如果你不想日志里满是莫名其妙的错误就最好避免把本地域资源权限直接指派给别的域的全局组和通用组。尽量把域内权限相同的帐号总结在全局组内,再把全局组加入实现功能的各个域本地组。在多域环境把权限相同的全局组加入通用组。组的嵌套不要太过于复杂,尽管有时候这很难把握。我很希望你看到这里的时候能高兴的说,哇,我完全懂了。 尽管我也知道这不太显示,老实说这难点不在概念上,而在应用上。其实除了这些组之外还有系统的内置组,除了内置的域本地组还有内置全局组,通用组。除此之外还有内置的系统组(Builtin Security Principal)据个例子,论坛里有个老兄面试的时候就遇到过----------“EXCH DOMAIN

SERVERS

EXCH ENTERPRISE SERVERS只见的区别和作用?是否可以移动到其他的容器?”怎么样?这两个组是安装Exchange之后自动产生的。EXCH DOMAIN SERVERS

是全局组,而EXCH ENTERPRISE SERVERS是本地域.而且EXCH DOMAIN SERVERS

属于EXCH ENTERPRISE

是不允许移动这两个组和重命名的。--当然我第一次看到这个问题也吓了一跳,这也是听高手解答的。当然我并不是给了你一个钻牛角尖的方向。你还是理清楚前面的概念吧。有问题你还可以问,有高手愿意指点也欢迎。大家共同进步。说句题外话,如果想搞得很透彻最好还是多看看原理性的书,当然也要多实践。我在看Kerberos这本书之前对KDC,SID,SPN什么票证票据的非常莫名其妙,也奇怪为什么总要认证而且会过期之类,因为在查找微软的KB的时候常常会看到类似的解释,包括各种认证都觉得难以理解。从原理入手就能理解很多东西都是必要的。当然我看的这个书也还是很浅,我也没有足够的精力和智慧深入研究。呵呵。不过学习确实是令人愉快的一件事。其中作者举了一个很生动的例子来演示Kerberos事务处理的过程:一个间谍需要和他的间谍组织联系并交换情报,间谍发出了一个信号,组织决定派一个信使和他见面交换情报,当然间谍和信使互相都不认识他们都只认识组织的头子。以下是他们联系的过程1。信使先联系组织头子,发消息说“告诉一个只有你和那个间谍才知道的秘密”,2。间谍头子为了证明信使的身份是否真实会先验证该消息的真实性,他检验的结果--该消息使用信使的加密密钥(secret eneryption key)来加密的。3。头子给信使回信,这封信分为两个部分:第一部分是一个随机数,他是头子随便决定的并用信使的密钥加密,第二部分包含相同的随机数,信使的姓名,起草信的时间和日期以及信的有效期,这部分用间谍的密钥来加密。4。信使收到头子回信后用自己的密钥成功解出前半部分中的随机数。---当然如果解出的结果是乱码那说明这个头子是假的。信使把信收好去和间谍接头。5。两人见面后互通了姓名,信使把回信的后半部分交给间谍(原作者建议大家去看一下昆汀。塔伦迪诺拍的《水库狗》『Reservir Dogs』)5.1如果间谍用自己的密钥无法对后半部信件解码,他就知道信使是假的,所以开枪射信使。5.2如果能解码但是得到乱码,他就知道信被篡改了,他还会开枪射他。5.3如果能解码但是得到的信使姓名与刚才通报的不同,他依然开枪。5.4如果得到的随机数过去得到过,他还射他,5.5如果得到的有效期过期了,他会扔掉信走掉。6。很幸运没出现上述的情况,间谍会交给信使一封信,其中包含了间谍的姓名,当前时间以及信件中字母总数并用刚才那封信理头子的随机数编码--该随机数成了密钥。7。信使用随机数解码,如果解除不对他就会对间谍开枪。如果时间过期他也会。8。最后信使成功解码,内容可以接受,认证过程结束。两人开始交流情报。当然这个例子是用来理解身份验证的,并不是对Kerberos的解释。我很难找到类似的例子帮助楼主理解组。当然前面也有不错的例子了。剩下的只是动手了。问题描述:AGDLP策略是什么?问题回答:这个实际上就是在域中使用组的策略,它指将域用户的账号(A)添加到全局组(G)中,将全局组添加到域本地组(DL),然后给域本地组分配资源的权限(P)。这种策略提供了比较大的灵活性oryServices 命名空间 AD 编程 2007-06-15 14:13:36 阅读85 评论0 字号:大中小 订阅

oryServices 命名空间用以从托管代码简便地访问 Active Directory。该命名空间包含两个组件类,即 DirectoryEntry 和 DirectorySearcher,它们使用 Active Directory 服务接口 (ADSI) 技术。ADSI 是 Microsoft 提供的一组接口,作为使用各种网络提供程序的灵活的工具。无论网络有多大,ADSI 都可以使管理员能够相对容易地定位和管理网络上的资源。

此命名空间中的类可以与任何 Active Directory 服务提供程序一起使用。当前的一些提供程序包括 Internet 信息服务 (IIS)、轻量目录访问协议 (LDAP)、Novell NetWare 目录服务

(NDS) 和 WinNT。ADSI 是 Microsoft Active Directory 的编程接口,使应用程序能够只使用一个接口就可以与网络上的不同目录进行交互。使用 ADSI,可以创建一些应用程序,用以执行常见任务,如备份数据库、访问打印机和管理用户帐户Active Directory 是一种树结构。树中的每个节点包含一组属性。使用此命名空间可遍历、搜索和修改树,以及读取和写入节点的属性。DirectoryEntry 类封装 Active Directory 层次结构中的节点或对象。使用此类绑定到对象、读取属性和更新特性。DirectoryEntry 与帮助器类一起为生存期管理和导航方法提供支持,包括创建、删除、重命名、移动子节点和枚举子级。DirectoryEntry 类备注使用该类绑定到对象,或读取和更新属性。DirectoryEntry,与帮助器类一起,为生存期管理和导航方法提供支持。这些包括创建、删除、重命名、移动子节点和枚举子级。修改节点之后,必须提交更改,以便将它们保存到树中。可以使用 DirectoryEntry 访问架构项中的常规项和一些(但不是所有)信息。Active Directory 层次结构包含多达数千个节点。每个节点表示一个对象,如网络打印机或域中的用户。公司网络会因为聘用新员工和添加对象(如网络打印机和计算机)而经常发生变化。Active Directory 服务接口 (ADSI) 技术提供了以编程方式向目录树中添加这些对象的途径。若要在层次结构中创建目录项,请使用 Children 属性。Children 属性是一个集合,提供

Add 方法,通过该方法将节点直接添加到当前绑定到的父节点之下的集合。当向集合中添加节点时,必须指定新节点的名称以及要与该节点相关联的架构模板的名称。例如,您可能需要使用标题为“Computer”的架构在层次结构中添加新的计算机。该类还包含属性缓存,这对于优化网络流量十分有用。与 DirectoryEntry 组件关联的类可以与任何 Active Directory 服务提供程序一起使用。当前的一些提供程序包括 Internet 信息服务 (IIS)、轻量目录访问协议 (LDAP)、Novell NetWare

目录服务 (NDS) 和 WinNT。使用 DirectorySearcher 类对 Active Directory 层次结构执行查询。LDAP 是系统提供的唯一一种支持搜索的 Active Directory 服务接口 (ADSI) 提供程序。Active Directory备注使用轻量目录访问协议 (LDAP) 并使用 DirectorySearcher 对象对 Active Directory 层次结构进行搜索和执行查询。LDAP 是系统提供的唯一支持目录搜索的 Active Directory 服务接口

(ADSI) 提供程序。管理员可以创建、更改和删除在层次结构中找到的对象Active Directory编程详解 AD 编程 2007-06-18 10:24:23 阅读57 评论0 字号:大中小 订阅

24.4 Active Directory编程要开发Active Directory程序,必须导入oryServices命名空间。还必须引用oryServices程序集。使用这个程序集中的类可以查询对象、查看和更新属性,搜索对象,把对象移动到其他容器对象中等。在下面的代码段中,简单的C#控制台应用程序说明了如何使用oryServices命名空间中的类。本节将介绍:●

oryServices命名空间中的类● 连接Active Directory的处理方式:绑定● 获取目录项,创建新对象,并更新已有的项目● 搜索Active Directory24.4.1 oryServices命名空间中的类表24-1列出了oryServices命名空间中的主要类。表

24-1类DirectoryEntry说 明这个类是oryServices命名空间中的主类。这个类的对象表示Active Directory库中的一个对象。使用这个类可以绑定对象,查看和更新属性。对象的属性都放在PropertyCollection中。PropertyCollection中的每个元素都有一个PropertyValueCollectionDirectoryEntries是DirectoryEntry对象的一个集合。DirectoryEntry对象的Children属性返回DirectoryEntries集合中DirectoryEntries的一个对象列表DirectorySearcher这个类主要用于用指定的属性搜索对象。要定义该搜索,可以使用SortOption类和枚举SearchScope、SortDirection

ReferalChasingOption。搜索的结果是一个SearchResult或SearchResultCollection。也可以得到ResultPropertyCollection

ResultPropertyValueCollection对象24.4.2

绑定要获得Active Directory中一个对象的值,必须连接Active Directory服务。这个连接过程称为绑定,绑定路径如下所示。LDAP:///OU=Development, DC= AthenaProject, DC=Com在绑定过程中,可以指定下述内容:● 指定提供程序使用的协议(protocol)。● 域控制器的服务器名(server name)。● 服务器过程的端口号(port number)。● 对象的显名(distingunshed name),以标识要访问的对象。● 如果需要访问Active Directory的用户不是运行当前进程的账户,则提供用户名和密码。● 如果需要加密,应指定authentication类型。下面详细介绍这些内容。1. 协议绑定路径的第一部分指定ADSI提供程序。该提供程序是一个COM服务器;prog-id的标识信息在注册表的HKEY_CLASSES_ROOT下。Windows XP附带的提供程序如表24-2所示。2. 服务器名在绑定路径中,服务器名在协议的后面。如果用户登录到Active Directory域上,服务器名就是可选的。如果不提供服务器名,就会发生无服务器绑定操作,此时Windows Server 2003会在域中查找与用户绑定过程相关的、“最好的”域控制器。如果站点中没有服务器,就使用查找到的第一个域控制器。无服务器的绑定如下所示:LDAP://OU=Sales,DC=AthenaProject,DC=Local表

24-2协 议LDAP说 明LDAP服务器,例如Exchange目录和Windows 2000 Server或Windows Server 2003 Active Directory服务器GCGC用于访问Active Directory中的全局目录。它也可以用于快速查询IISWinNT使用IIS的ADSI提供程序,可以在IIS目录中创建和管理新网站要访问旧Windows NT 4域的用户数据库,可以使用WinNT

的ADSI提供程序。NT4用户只有几个属性没有改变。也可以使用这个协议绑定Windows 2000域,但这里也限制了可用于NT4的属性这个progID用于和Novell Directory Services通信使用NWCOMPAT可以访问旧的Novell目录,例如Novell Netware COMPAT3. 端口号在服务器名的后面,可以指定服务器过程的端口号,其语法是:xxx。LDAP服务器的默认端口号是端口389: LDAP://:389。Exchange服务器使用的端口号与LDAP服务器一样。如果在同一个系统上安装了Exchange服务器,例如用作Active Directory的域控制器,就可以配置另一个端口。4. 显名在路径中指定的第四部分是显名(distinguished name,DN)。显名是一个惟一的名称,标识要访问的对象。在Active Directory中,可以使用基于X.500的LDAP语法,指定对象的名称。例如有一个显名:CN=Christian Nagel, OU=Consultants, DC= AthenaProject, DC=local这个显名指定域中域组件(Domain Component,DC) AthenaProject的组织单元(Organizational Unit,OU) Consultants的公共名称(Common Name,CN) Christian

Nagel。最右边的部分是域的根对象。该名称必须符合对象树中的分层方式。显名的字符串表示的LDAP规范在 RFC 2253( /rfc/)上。(1) 相对显名相对显名(RDN)用于引用容器对象中的对象。使用RDN时,不需要指定OU和DC,有一个公共名称就足够了。CN=Christian Nagel就是组织单元中的一个相对显名。如果已经引用了一个容器对象,要访问其子对象,就可以使用相对显名。(2) 默认的命名环境如果在路径中没有指定显名,绑定过程就会使用默认的命名环境(default naming context)。使用rootDSE可以读取默认命名环境。LDAP 3.0把rootDSE定义为目录服务器中目录树的根。例如LDAP://rootDSE

或:LDAP://servername/rootDSE

通过列举rootDSE的所有属性,将获得没有指定名称时可以使用的defaultNamingContext信息。schemaNamingContext 和 configurationNamingContext指定了用于访问模式所需要的名称和Active Directory库中的配置。通过下面的代码可获得rootDSE的所有属性:using (DirectoryEntry de = new DirectoryEntry()){ = "LDAP://platinum/rootDSE";me = @" platinumchristian";rd = "password";PropertyCollection props = ties;foreach (string prop in tyNames){PropertyValueCollection values = props[prop];foreach (string val in values){(prop + ": ");ine(val);}}}这个程序显示了默认的命名环境(defaultNamingContext DC=eichkogelstrasse、 DC=local),用于访问模式的环境(CN=Schema、 CN=Configuration、 DC=eichkogelstrasse、 DC=local)和配置的命名环境(CN=Configuration、 DC=eichkogelstrasse、 DC=local),如图24-9所示。图

24-9(3) 对象标识符每个对象都有一个全局惟一的标识符GUID。GUID是一个惟一的128位数字,您可能已经在COM开发中了解了它。可以使用GUID绑定一个对象。这样,即使对象移动到另一个容器中,也可以得到该对象。GUID在创建对象时生成,且总是保持不变。使用Guid可以得到GUID的字符串表示。这个字符串表示就可以用于绑定对象。下面的示例显示了一个无服务器绑定的路径名称,它绑定到GUID代表的一个特定对象上:LDAP://(4) Windows NT域中的对象名WinNT提供程序不允许在绑定字符串的名称部分使用LDAP语法。在这个提供程序中,对象用ObjectName、ClassName指定。Windows NT域的有效绑定字符串如下:WinNT:WinNT://DomainNameWinNT://DomainName/UserName, userWinNT://DomainName/ServerName/MyGroup, groupuser和group后缀指定可以访问类型为user或group的对象。5. 用户名有时,在访问目录时,必须使用一个非当前进程的用户名(也许这个用户没有访问Active

Directory所必须的许可),此时必须为绑定过程显式指定用户证书(user credential)。Active

Directory提供了许多方式来设置用户名。(1) Downlevel登录使用downlevel登录,用户名可以用Windows 2000以前的域名来指定:domainusername(2) 显名也可以用user对象的显名来指定用户,例如:CN=Administrator,

CN=Users,DC=athenaproject,DC=local(3) User Principal Name (UPN)对象的UPN用userPrincipalName属性来定义。系统管理员可以在Active Directory Users and

Computers工具中User属性的Account选项卡上,用登录信息来指定UPN,注意这不是用户的电子邮件地址。这些信息也惟一地标识了用户,可以用于登录:Nagel@ 6. 身份验证为了给身份验证进行安全的加密,也可以指定身份验证(authentication)类型。身份验证可以用DirectoryEntry类的AuthenticationType属性设置。可以指定其值为AuthenticationTypes枚举中的一个值。因为枚举是用属性[Flags]标识的,所以可以指定多个值。其可能的值有:对发送的数据进行加密的ReadonlyServer,它指定只需要读取访问,Secure表示安全的身份验证。7. 用DirectoryEntry类绑定oryEntry类可以用于指定所有的绑定信息。可以使用默认的构造函数,用Path、Username、Password和 AuthenticationType属性定义绑定信息,或者把这些信息传递给构造函数:DirectoryEntry de = new DirectoryEntry(); = "LDAP://platinum/DC=athenaproject, DC=local";me = "nagel@ ";rd = "password";// use the current user credentialsDirectoryEntry de2 = new DirectoryEntry("LDAP://DC= athenaproject, DC=local");即使成功地构造了DirectoryEntry对象,也并不意味着绑定成功了。在第一次读取属性时进行绑定,可以避免不必要的网络流通量。对象是否存在,或者指定的用户证书是否正确,都可以在第一次访问该对象时确定。24.4.3 获取目录项前面介绍了如何指定Active Directory中对象的绑定属性,下面要读取对象的属性。在下面的示例中要读取用户对象的属性。DirectoryEntry类的一些属性可以提供对象的信息,即Name、Guid和 SchemaClassName属性。第一次访问DirectoryEntry对象的属性时,会执行绑定操作,并填充底层ADSI对象的缓存。后面将详细讨论这些。其他属性可以从缓存中读取,同一对象的数据不需要通过与服务器的通信来获得。在本例中,用组织单元Wrox Press中的公共名称Christian Nagel访问一个用户对象:using (DirectoryEntry de = new DirectoryEntry()){ = "LDAP://platinum/CN=Christian Nagel, " +

"OU=Wrox Press, DC=athenaproject, DC=local";ine("Name: " + );ine("GUID: " + );ine("Type: " + ClassName);ine();//...}Active Directory对象包含许多信息,这些信息取决于对象的类型。属性Properties将返回一个PropertyCollection。每个属性本身就是一个集合,因为一个属性可以有多个值,例如,user对象可以有多个电话号码。在本例中,用一个内部foreach循环查看这些值。从properties[name]返回的集合是一个object数组。属性值可以是字符串、数字或其他类型。使用ToString()方法就可以显示这些值:ine("Properties: ");PropertyCollection properties = ties;foreach (string name in tyNames){foreach (object o in properties[name]){ine(name + ": " + ng());}}在得到的结果中,包含了user对象Christian Nagel的所有属性,如图24-10所示。OtherTelephone是一个多值属性,它包含许多电话号码。一些属性值只显示System._ComObject对象的类型,例如,lastLogoff、lastLogon和nTSecurityDescriptor。要得到这些属性的值,必须直接使用oryServices命名空间的类中的ADSI COM接口。图

24-10注意:第28章介绍了如何使用COM对象和接口。2. 直接通过名称访问属性使用 ties可以访问所有属性。如果已知属性名,就可以直接访问其值:foreach (string homePage in ties["wWWHomePage"])ine("Home page: " + homePage);24.4.4 对象集合对象在Active Directory中是分层存储的。容器对象包含子对象。使用DirectoryEntry类的Children属性可以枚举容器中的子对象。另一方面,使用Parent属性可以得到对象的容器。用户对象没有子对象,所以下面的示例使用一个组织单元,如图24-11所示。非容器对象用Children属性返回一个空集合。下面在域的组织单元Wrox Press中获得其所有的用户对象。Children属性返回一个DirectoryEntries集合,其中包含DirectoryEntry对象。迭代所有的DirectoryEntry对象,显示子对象的名称。using (DirectoryEntry de = new DirectoryEntry()){ = "LDAP://platinum/OU=Wrox Press, " +

"DC=athenaproject, DC=local";ine("Children of " + );foreach (DirectoryEntry obj in en){ine();}}图

24-11本例显示了组织单元中的所有对象:users、contacts、printers、shares和其他组织单元。如果只需要查看某些对象类型,可以使用DirectoryEntries类的SchemaFilter属性。SchemaFilter属性返回一个SchemaNameCollection。有了这个SchemaNameCollection,就可以使用Add()方法定义要查看的对象类型。在本例中,因为只需要查看user对象,所以把user添加到这个集合中:using (DirectoryEntry de = new DirectoryEntry())

{ = "LDAP:// platinum /OU=Wrox Press, " +

"DC= athenaproject, DC=local";ine("Children of " + );("user");foreach (DirectoryEntry obj in en){ine();}}结果,只显示组织单元中的user对象,如图24-12所示。24.4.5 缓存要减少网络流通量,ADSI使用缓存来存储对象属性。如前所述,在创建DirectoryEntry对象时,是不访问服务器的。只要从目录库中读取第一个属性,所有的属性都会写到缓存中,这样,在读取下一个属性时,就不需要往返于服务器了。写入对象的改变,只会改变已缓存的对象。设置属性不会产生网络流通量。必须使用Changes()才能刷新缓存,把所有已改变的数据传送回服务器。要再次从目录库中获取新写入的数据,可以使用hCache()读取属性。当然,如果没有调用CommitChanges() 和RefreshCache()就修改了一些属性,所有的改变都会丢失,因为我们将再次使用RefreshCache()读取目录服务中的值。把属性pertyCache设置为false,就可以关闭这个属性cache。但除非在进行调试,否则最好不要关闭它,因为这会与服务器间产生许多不必要的往返通信。24.4.6 创建新对象创建新Active Directory对象时,例如users、computers、printers和contacts等,可以使用DirectoryEntries类以编程的方式来完成创建工作。要给目录添加新对象,首先必须绑定一个容器对象,例如组织单元,可以在其中插入一个新对象。不包含其他对象的对象是不能使用的。下面使用一个容器对象,其显名为CN=Users,DC= athenaproject,DC=local:DirectoryEntry de = new DirectoryEntry(); = "LDAP://platinum/CN=Users, DC= athenaproject, DC=local";使用DirectoryEntry的Children属性,可以得到一个DirectoryEntries对象:DirectoryEntries users = en;使用DirectoryEntries,可以添加、删除和查找集合中的对象。下面创建一个新的user对象。使用Add()方法时,需要一个对象名和一个类型名。使用ADSI Edit很容易获得类型名:DirectoryEntry user = ("CN=John Doe", "user");对象现在有了默认属性值。要指定特定的属性值,可以使用Properties属性的Add()方法添加属性。当然,所有的属性都必须存在于user对象的模式中。如果指定的属性不存在,就得到一个COMException“指定的目录服务属性或值不存在”:ties["company"].Add("Some Company");ties["department"].Add("Sales");ties["employeeID"].Add("4711");ties["samAccountName"].Add("JDoe");ties["userPrincipalName"].Add("JDoe@ ");ties["givenName"].Add("John");ties["sn"].Add("Doe");ties["userPassword"].Add("someSecret");此时,为了把数据写入Active Directory,必须刷新缓存中的数据:Changes();24.4.7 更新目录项Active Directory服务中对象的更新和读取一样简单。可以在读取对象后修改它们的值。要删除一个属性的所有值,可以调用()方法。使用Add(),可以把新值添加到属性中。Remove()和RemoveAt()可以从属性集合中删除指定的值。要修改一个值,可以把这个值设置为指定的值。下面的代码将通过PropertyValueCollection的一个索引符把移动电话号码设置为一个新值。使用该索引符,只能改变已存在的值。因此,应使用ns()来确定属性是否可用。using (DirectoryEntry de = new DirectoryEntry()){ = "LDAP://platinum /CN=Christian Nagel, " +"OU=Wrox Press, DC= athenaproject, DC=local";if (ns("mobile")){ties["mobile"][0] = "+43(664)3434343434";}else{ties["mobile"].Add("+43(664)3434343434");}Changes();}在本例的else部分,如果移动电话号码不存在新属性,就用方法PropertyValue

()添加它。如果使用Add()方法和已有的属性,得到的结果将取决于属性的类型:单值属性或多值属性。使用Add()方法和已有的单值属性,会得到一个COMException:A constraint violation occurred。使用Add()方法和已有的多值属性则会成功地把另一个值添加到属性中。User对象的属性mobile定义为单值属性,所以不能添加其他移动电话的号码。但是用户可以有多个移动电话的号码。对于多个移动电话的号码,可以使用属性otherMobile,它是一个多值属性,允许设置多个移动电话号码,所以可以调用Add()多次。多值属性有一个重要的检查:即检查其唯一性。如果把第二个电话号码添加到同一个user对象上,也会得到一个COMException:指定的目录服务属性或值已经存在。提示:在创建或更新新的目录对象后,应调用Changes()。否则只能更新缓存中的信息,改变的信息不会发送到目录服务上。24.4.8 访问内部的ADSI对象调用预定义的ADSI接口方法常常比搜索对象的属性名容易得多。一些ADSI对象还支持不能在DirectoryEntry类中直接使用的方法。例如IADsServiceOperations接口有启动和停止Windows服务的方法。Windows服务将在第32章讨论。如本章前面所述,oryServices命名空间的类使用底层的ADSI COM对象。DirectoryEntry支持直接使用Invoke()方法调用底层对象的方法。Invoke()的第一个参数是应在ADSI对象中调用的方法名,第二个参数的params关键字允许把数量可变的其他参数传送给ADSI方法:public object Invoke(string methodName, params object[] args);

在ADSI文档中介绍了可以用Invoke()方法调用的方法。域中的每个对象都支持IADS接口的方法。前面创建的User对象也支持IADsUser接口的方法。在下面的代码示例中,使用方法sword()改变前面创建的user对象的密码:using (DirectoryEntry de = new DirectoryEntry()){ = "LDAP://platinum /CN=John Doe, " +

"CN=Users, DC= athenaproject, DC=local";("SetPassword", "anotherSecret");Changes();}如果不使用Invoke(),还可以直接使用底层的ADSI对象。要使用这些对象,必须使用Project | Add Reference添加对Active DS Type Library的引用,如图24-13所示。这会创建一个包装器类,在该类中可以访问ActiveDS命名空间中的这些对象。图

24-13内部对象可以使用DirectoryEntry类的NativeObject属性来访问。在下面的示例中,对象de是一个user对象,所以可以把它强制转换为er。SetPassword()是在IADsUser接口中说明的方法,所以可以直接调用它,而不是使用Invoke()方法来调用。把IADsUser的AccountDisabled属性设置为false,就可以激活账户。与前面的示例一样,调用CommitChanges() 和DirectoryEntry对象,把改变的内容写到目录服务中:er user = (er)Object;sword("someSecret");tDisabled = false;Changes();24.4.9

在Active Directory中搜索Active Directory是一个数据库,它为大多数读取访问进行了优化,所以一般应使用搜索一些值。要在Active Directory中搜索,可以使用.NET Framework中的类DirectorySearcher。注意:DirectorySearcher只能和LDAP提供程序一起使用。它不能和NDS或IIS提供程序一起使用。在类DirectorySearcher的构造函数中,可以定义搜索的4个重要部分。也可以使用默认构造函数,用属性定义搜索选项。1. SearchRootSearchRoot指定搜索应从什么地方开始。SearchRoot的默认值是当前使用的域的根。SearchRoot用DirectoryEntry对象的Path指定。2. 过滤器过滤器定义了希望有的值。过滤器是一个必须放在括号中的字符串。表达式中可以使用关系运算符,如<=、 =、 >=。(objectClass=contact)会搜索所有类型为contact的对象,(lastName>=Nagel) 会按字母表的顺序搜索lastName属性等于或大于Nagel的所有对象。表达式可以和前缀运算符 & 和 |组合使用。例如,(&(objectClass=user)(description=Auth*))搜索类型为User,其属性description以字符串Auth开头的所有对象。因为 & 和 | 运算符在表达式的开头,所以可以把多个表达式用一个前缀运算符组合在一起。默认过滤器是(objectClass=*),所以将选择所有的对象。注意:过滤器语法在RFC 2254中定义为“LDAP搜索过滤器的字符串表示”。这个RFC在/rfc/中。3. PropertiesToLoad使用PropertiesToLoad,可以定义所有属性的StringCollection。对象可以有许多属性,其中的大多数对于搜索请求都不太重要。我们定义了应加载到缓存中的属性。如果没有指定属性,默认属性就应是对象的Path 和Name属性。4. SearchScopeSearchScope 是一个枚举,定义了搜索应延伸的深度:●

只搜索对象中的属性,至多可以得到一个对象。●

el表示在基对象的子集合中继续搜索。基对象本身是不搜索的。●

e定义了在整个树中搜索。SearchScope属性的默认值是e。5. 搜索的限制在目录服务中搜索特定的对象可以在几个域中进行。对搜索要限制对象的个数或搜索时间,可以定义其他几个属性(如表24-3所示)。表 24-3属 性ClientTimeout说 明客户机等待服务器返回结果的最长时间。如果服务器没有响应,就不返回记录使用

paged search,服务器会返回用PageSize

定义的许多对象,而不是所有的对象。这会减少客户获得第一个答案的时间和需要的内存,服务器把一个cookie送给客户机,客户机再把下一个搜索请求发送回服务器,这样搜索就可以在上一次结PageSize束的地方继续进行ServerPageTimeLimit对于paged search,这个值定义了一个搜索时间,在该时间内返回用PageSize

值定义的许多对象。如果这段时间在PageSize值之前到达,就会把此时查找到的对象返回给客户机。默认值为-1,表示时间为无限定义服务器搜索对象的最长时间。过了这段时间后,就会把此时查找到的所有对象返回给客户机。默认值是120秒,不能把搜索时间设置为较高的值搜索可以在几个域中进行。如果用SearchRoot

指定的根是一个父域或没有指定根,就会继续在子域中搜索。使用这个属性可以指定是否应在不同的服务器上继续搜索表示不能在不同的服务器上继续搜索inate指定继续在子域中搜索,搜索ServerTimeLimitReferalChasing从DC=Wrox、DC=COM开始时,服务器可以返回一个结果集,例如DC=France、DC=Wrox、DC=COM引用。客户机可以继续在子域中搜索al表示服务器可以让客户机搜索不在子域中的另一个服务器,这是默认选项表示返回外部和从属的引用在搜索示例中,要搜索组织单元Wrox Press中description属性值为Author的所有user 对象。首先,绑定组织单元Wrox Press,在该组织单元中开始搜索。创建一个DirectorySearcher对象,在其中设置SearchRoot。过滤器定义为(&(objectClass=user) (description=Auth*)),这样就可以搜索所有类型为User、description属性以Auth开头的对象。搜索的范围应在一个子树中,即在Wrox Press的子组织单元中搜索:using (DirectoryEntry de =

new DirectoryEntry("LDAP://OU=Wrox Press, DC= athenaproject, DC=local"))using (DirectorySearcher searcher = new DirectorySearcher()){

Root = de; = "(&(objectClass=user)(description=Auth*))";Scope = e;要在搜索结果中包含的属性有name、description、givenName和WWWHomePage。("name");("description");("givenName");("wWWHomePage");下面准备开始搜索。还应对结果进行排序。DirectorySearcher有一个属性Sort,它可以设置SortOption。SortOption构造函数的第一个参数定义了要排序的属性,第二个参数定义了排序的方向。SortDirection枚举的值是Ascending 和 Descending。要开始搜索,可以使用FindOne()方法查找第一个对象,或者使用FindAll()。FindOne()返回一个简单的SearchResult,FindAll()返回一个SearchResultCollection。要得到所有的作者对象,就应使用FindAll(): = new SortOption("givenName", ing);SearchResultCollection results = l();使用一个foreach循环,可以访问SearchResultCollection中的每个SearchResult。一个SearchResult表示搜索缓存中的一个对象。Properties属性返回一个ResultPropertyCollection,使用属性名和索引符可以访问该集合中所有的属性:SearchResultCollection results = l();foreach (SearchResult result in results){ResultPropertyCollection props = ties;foreach (string propName in tyNames){(propName + ": ");ine(props[propName][0]);

}ine();}}可以在搜索之后获得完整的对象:SearchResult有一个方法GetDirectoryEntry(),它返回查找到的对象的相应DirectoryEntry。得到的结果应显示《Professional C#》(即《C#高级编程》)的作者列表,这些作者都有我们指定的属性,如图24-14所示。24.5

搜索用户对象本章的最后一节要创建一个Windows Forms应用程序UserSearch。这个应用程序是非常灵活的,因为可以输入特定的域控制器、用户名和密码,以访问Active Directory,或者使用运行进程的用户。在这个应用程序中,我们将访问Active Directory服务的模式,获得user对象的属性。该用户可以输入一个过滤器字符串,搜索域中的所有user对象。还可以设置应显示的user对象的属性。24.5.1 用户界面用户界面显示了一些已编好序号的步骤,说明如何使用该应用程序(如图24-15所示):图

24-15● 在第一步中,输入用户名、密码和域控制器。所有这些信息都是可选的。如果没有输入域控制器,就要使用无服务器绑定进行连接。如果没有输入用户名,就使用当前用户的安全环境。● 使用一个按钮,就可以把User对象的所有属性名动态加载到listBoxProperties

列表 框中。● 在加载了属性名后,就可以选择要显示的属性。列表框的SelectionMode设置为MultiSimple。● 可以输入限制搜索的过滤器,在该对话框中设置的默认值是搜索所有的user对象:(objectClass=user)。● 现在开始搜索。24.5.2 获取模式命名环境这个应用程序只有两个处理程序方法:按钮的第一个处理程序方法加载属性,第二个处理程序方法则在域中开始搜索操作。在第一部分,从模式中动态读取User类的属性,在用户界面中显示它。在处理程序方法buttonLoadProperties_Click()中,使用SetLogonInformation()从对话框中读取用户名、密码和主机名,并存储在类的成员中。接着,SetNamingContext()方法设置模式的LDAP名称和默认环境的LDAP名称。这个模式LDAP名称用于调用中,以设置列表框中的属性SetUserProperties()。private void buttonLoadProperties_Click(object sender, rgs e){try{SetLogonInformation();SetNamingContext();SetUserProperties(schemaNamingContext);}catch (Exception ex){("Check your inputs! " + e);}}protected void SetLogonInformation(){username = ( == ""password = ( == ""hostname = ;if (hostname != "") hostname += "/";}在帮助方法SetNamingContext()中,使用目录树的根来获得服务器的属性。这里只考虑两个属性的值:schemaNamingContext 和 defaultNamingContext。protected string SetNamingContext(){using (DirectoryEntry de = new DirectoryEntry()){string path = "LDAP://" + hostname + "rootDSE";me = username;rd = password; = path;schemaNamingContext = ties["schemaNamingContext"][0].ToString();defaultNamingContext =

ties["defaultNamingContext"][0].ToString();}}24.5.3 获取User类的属性名使用LDAP名称可以访问模式。使用它可以访问目录,并读取属性。我们不仅要介绍User类的属性,还将介绍User的基类:Organizational-Person、Person和Top。在这个程序中,基类的名称是硬编码的。还可以使用subClassOf属性动态读取基类。GetSchemaProperties()返回一个字符串数组和指定对象类型的所有属性名。这些属性名都在StringCollection属性中:protected void SetUserProperties(string schemaNamingContext){StringCollection properties = new StringCollection();string[] data = GetSchemaProperties(schemaNamingContext, "User");ge(GetSchemaProperties(schemaNamingContext,

"Organizational-Person"));ge(GetSchemaProperties(schemaNamingContext, "Person"));ge(GetSchemaProperties(schemaNamingContext, "Top"));();foreach (string s in properties){(s);}}在GetSchemaProperties()中,再次访问Active Directory服务。这次不使用rootDSE,而使用前面介绍的模式的LDAP名称。属性systemMayContain包含objectType类中的所有属性的一个集合:protected string[] GetSchemaProperties(string schemaNamingContext,

string objectType){string[] data;using (DirectoryEntry de = new DirectoryEntry()){me = username;rd = password; = "LDAP://" + hostname + "CN=" + objectType + "," +

schemaNamingContext;tyCollection properties = ties;tyValueCollection values = properties["systemMayContain"];data = new String[];(data, 0);}return data;}注意上述代码中的tyCollection,这是因为在Windows Forms应用程序中,oryServices命名空间中的PropertyCollection类与tyCollection的名称相冲突。为了避免使用像tyCollection这么长的名称,可以使用下面的代码来缩短命名空间的名称:using DS = oryServices;这样就完成了应用程序的第二步。Listbox控件包含User对象的所有属性名。24.5.4 搜索用户对象搜索按钮的处理程序只调用帮助方法FillResult();private void buttonSearch_Click(object sender, rgs e){try{FillResult();}catch (Exception ex){("Check your input: " + e);}}在FillResult()中,在整个Active Directory 域中进行与前面一样的正常搜索。SearchScope设置为Subtree, Filter设置为TextBox中的字符串,应加载到缓存中的属性由用户在列表框中选择的值来设置。方法GetProperties()用于把属性数组传送给方法searcher。PropertiesTo

ge()是一个帮助方法,它从列表框中把选中的属性度到一个数组中。在设置了DirectorySearcher对象的属性后,就调用SearchAll()方法搜索属性。SearchResultCollection中的搜索结果用于生成写到文本框textBoxResults中的汇总信息。protected void FillResult(){using (DirectoryEntry root = new DirectoryEntry()){me = username;rd = password; = "LDAP://" + hostname + defaultNamingContext;using (DirectorySearcher searcher = new DirectorySearcher()){Root = root;Scope = e; = ;ge(GetProperties());SearchResultCollection results = l();StringBuilder summary = new StringBuilder();foreach (SearchResult result in results){foreach (string propName in

tyNames){foreach (string s in ties[propName]){(" " + propName + ": " + s + "rn");}}("rn");} = ng();}}}启动该应用程序,将列出所有由过滤器选择的有效对象,如图24-16所示。24.6

小结本章介绍了Active Directory的体系结构,有关域、树和森林的重要概念。利用它,我们可以访问整个企业的信息。在编写访问Active Directory服务的应用程序时,必须注意读取的数据可能不是最新的,因为进行复制操作时有一定的等待时间。使用oryServices命名空间中的类,可以很容易地访问封装到ADSI提供程序中的Active Directory服务。DirectoryEntry类可以直接读写数据库中的对象。使用DirectorySearcher类可以进行复杂的搜索,定义过滤器、超时、加载的属性和范围等。使用全局目录,可以加快对整个企业中的对象的搜索,因为它在森林中存储了所有对象的只读版本。