24.4 Active Directory编程
要开发Active Directory程序,必须导入System.DirectoryServices命名空间。还必须引用System.DirectoryServices程序集。使用这个程序集中的类可以查询对象、查看和更新属性,搜索对象,把对象移动到其他容器对象中等。在下面的代码段中,简单的C#控制台应用程序说明了如何使用System.DirectoryServices命名空间中的类。
本节将介绍:
● System.DirectoryServices命名空间中的类
● 连接Active
Directory的处理方式:绑定
● 获取目录项,创建新对象,并更新已有的项目
● 搜索Active
Directory
24.4.1 System.DirectoryServices命名空间中的类
表24-1列出了System.DirectoryServices命名空间中的主要类。
表 24-1
类 |
说 明 |
DirectoryEntry |
这个类是System.DirectoryServices命名空间中的主类。这个类的对象表示Active |
DirectoryEntries |
DirectoryEntries是DirectoryEntry对象的一个集合。DirectoryEntry对象的Children属性返回DirectoryEntries集合中的一个对象列表 |
DirectorySearcher |
这个类主要用于用指定的属性搜索对象。要定义该搜索,可以使用SortOption类和枚举SearchScope、SortDirection 和ReferalChasingOption。搜索的结果是一个SearchResult或SearchResultCollection。也可以得到ResultPropertyCollection 和 ResultPropertyValueCollection对象 |
24.4.2 绑定
要获得Active Directory中一个对象的值,必须连接Active Directory服务。这个连接过程称为绑定,绑定路径如下所示。
LDAP://dc01.athenaproject.com/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 |
GC |
GC用于访问Active Directory中的全局目录。它也可以用于快速查询 |
IIS |
使用IIS的ADSI提供程序,可以在IIS目录中创建和管理新网站 |
WinNT |
要访问旧Windows NT 4域的用户数据库,可以使用WinNT 的ADSI提供程序。NT4用户只有几个属性没有改变。也可以使用这个协议绑定Windows |
NDS |
这个progID用于和Novell |
NWCOMPAT |
使用NWCOMPAT可以访问旧的Novell目录,例如Novell |
3. 端口号
在服务器名的后面,可以指定服务器过程的端口号,其语法是:xxx。LDAP服务器的默认端口号是端口389: LDAP://dc01.globalknowledge.net:389。Exchange服务器使用的端口号与LDAP服务器一样。如果在同一个系统上安装了Exchange服务器,例如用作Active Directory的域控制器,就可以配置另一个端口。
4. 显名
在路径中指定的第四部分是显名(distinguished name,DN)。显名是一个惟一的名称,标识要访问的对象。在Active Directory中,可以使用基于X.500的LDAP语法,指定对象的名称。
例如有一个显名:
CN=Christian Nagel, OU=Consultants, DC= AthenaProject, DC=local
这个显名指定域AthenaProject.local中域组件(Domain Component,DC) AthenaProject的组织单元(Organizational Unit,OU) Consultants的公共名称(Common Name,CN) Christian Nagel。最右边的部分是域的根对象。该名称必须符合对象树中的分层方式。
显名的字符串表示的LDAP规范在 RFC 2253( http://www.ietf.org/rfc/rfc2253.txt)上。
(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())
{
de.Path = "LDAP://platinum/rootDSE";
de.Username = @" platinum\christian";
de.Password = "password";
PropertyCollection props = de.Properties;
foreach (string prop in props.PropertyNames)
{
PropertyValueCollection values = props[prop];
foreach (string val in values)
{
Console.Write(prop + ": ");
Console.WriteLine(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在创建对象时生成,且总是保持不变。
使用DirectoryEntry.NativeGuid可以得到GUID的字符串表示。这个字符串表示就可以用于绑定对象。
下面的示例显示了一个无服务器绑定的路径名称,它绑定到GUID代表的一个特定对象上:
LDAP://<GUID=14abbd652aae1a47abc60782dcfc78ea>
(4) Windows NT域中的对象名
WinNT提供程序不允许在绑定字符串的名称部分使用LDAP语法。在这个提供程序中,对象用ObjectName、ClassName指定。Windows NT域的有效绑定字符串如下:
WinNT:
WinNT://DomainName
WinNT://DomainName/UserName, user
WinNT://DomainName/ServerName/MyGroup, group
user和group后缀指定可以访问类型为user或group的对象。
5. 用户名
有时,在访问目录时,必须使用一个非当前进程的用户名(也许这个用户没有访问Active Directory所必须的许可),此时必须为绑定过程显式指定用户证书(user credential)。Active Directory提供了许多方式来设置用户名。
(1) Downlevel登录
使用downlevel登录,用户名可以用Windows 2000以前的域名来指定:
domain\username
(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@ athenaproject.local
6. 身份验证
为了给身份验证进行安全的加密,也可以指定身份验证(authentication)类型。身份验证可以用DirectoryEntry类的AuthenticationType属性设置。可以指定其值为AuthenticationTypes枚举中的一个值。因为枚举是用属性[Flags]标识的,所以可以指定多个值。其可能的值有:对发送的数据进行加密的ReadonlyServer,它指定只需要读取访问,Secure表示安全的身份验证。
7. 用DirectoryEntry类绑定
System.DirectoryServices.DirectoryEntry类可以用于指定所有的绑定信息。可以使用默认的构造函数,用Path、Username、Password和 AuthenticationType属性定义绑定信息,或者把这些信息传递给构造函数:
DirectoryEntry de = new DirectoryEntry();
de.Path = "LDAP://platinum/DC=athenaproject, DC=local";
de.Username = "nagel@ athenaproject.local";
de.Password = "password";
// use the current user credentials
DirectoryEntry 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())
{
de.Path = "LDAP://platinum/CN=Christian Nagel, " +
"OU=Wrox Press, DC=athenaproject, DC=local";
Console.WriteLine("Name: " + de.Name);
Console.WriteLine("GUI