C#通过LDAP访问目录服务

C#通过LDAP访问目录服务

本文介绍如何编写C#程序通过LDAP协议访问微软目录服务获得用户在目录中的属性信息。在开始部分先简单句介绍LDAP协议,然后是技术比较及实现部分。

目录

  • 什么是LDAP?
    • 简介
    • 概述
    • 协议内容
    • 产品
  • 查询用户信息
  • 用途

什么是LDAP?

简介

LDAP是轻型目录访问协议(Lightweight Directory Access Protocol,/ˈɛldæp/),是一个开放的、中立的、工业标准的应用协议,通过IP协议提供访问控制和维护分布式信息的目录信息访问服务。

目录服务在开发内部网路和与互联网应用共享用户(用户组织)、系统、网络、服务和应用的过程中占据了重要地位。例如,目录服务提供了组织有序的记录集合,通常有层级结构,例如公司电子邮件目录。同理,也提供包含了地址和电话号码的电话簿。

LDAP由互联网工程任务组(IETF)的文档RFC定义,使用了描述语言ASN.1定义。最新的版本是版本3,由RFC 4511所定义。例如,一个用语言描述的LDAP的搜索如:“在公司邮件目录中搜索公司位于那什维尔名字中含有“Jessy”的有邮件地址的所有人。请返回他们的全名,电子邮件,头衔和简述。”

LDAP的一个常用用途是单点登录,用户可以在多个服务中使用同一个密码,通常用于公司内部网站的登录中(这样他们可以在公司计算机上登录一次,便可以自动在公司内部网上登录)。

LDAP基于X.500标准的子集。因为这个关系,LDAP有时被称为X.500-lite。

概述

鉴于原先的目录访问协议(Directory Access Protocol即DAP)对于简单的互联网客户端使用太复杂,IETF设计并指定LDAP做为使用X.500目录的更好的途径。LDAP在TCP/IP之上定义了一个相对简单的升级和搜索目录的协议。

常用词"LDAP目录"可能会被误解,而实际并没有"LDAP目录"这么一个目录种类。通常可以用它来描述任何使用LDAP协议访问并能用X.500标识符标识目录中对象的目录。

协议内容

LDAP目录与普通数据库结构的主要不同之处在于数据的组织方式,它是一种有层次的、树形结构。所有条目的属性的定义是对象类(object class)的组成部分,并组成在一起构成结构(schema);那些在组织内代表个人的结构被命名为白页结构(white pages schema)。数据库内的每个条目都与若干对象类联系,而这些对象类决定了一个属性是否为可选和它保存哪些类型的信息。属性的名字一般是一个易于记忆的字符串,例如用cn为通用名(common name)命名,而"mail"代表e-mail地址。属性取值依赖于其类型,并且LDAPv3中一般非二进制值都遵从UTF-8字符串语法。例如,mail属性包含值“user@example.com”;jpegPhotos属性一般包含JPEG/JFIF格式的图片。

LDAP目录条目可描述一个层次结构,这个结构可以反映一个政治、地理或者组织的范畴。在原始的X.500模型中,反应国家的条目位于树的顶端;接着是州或者民族组织。典型的LDAP配置使用DNS名称作为树形结构的顶端,下列是代表人、文档、组织单元、打印机和其他任何事务的条目。

LDAP影响了后续的Internet协议,包括新版本的X.500、Directory Services Markup Language (DSML)、Service Provisioning Markup Language (SPML)和Service Location Protocol.

产品

LDAP从下面厂商获得广泛支持:

  • Apache - Apache Directory Server
  • Apple(苹果) - Open Directory
  • AT&T
  • Banyan
  • HP(惠普)
  • IBM - IBM Lotus
  • ISODE - M-Vault Server
  • Microsoft(微软) - Active Directory
  • Netscape(网景) - Sun Microsystems和Red Hat的产品
  • Novell - eDirectory
  • OctetString - VDE Server
  • Oracle(甲骨文) - Oracle Internet Directory
  • Red Hat(红帽) - Fedora Directory Server
  • Siemens(西门子) - DirX Server
  • Sun - iPlanet Directory Server

此外还有开源/自由软件的实现——如Open LDAP、Apache HTTP Server使用代理服务器(通过模块mod_proxy)支持LDAP。

查询用户信息

技术选型

微软Windows活动目录的目录服务还是通过微软的技术框架来实现,无论从安全性和稳定性上都会有一定的保证,所以我们采用C#,当然你也可以使用C++实现,相信会有更好的性能提升。

目录服务程序集

这里我们介绍一下目录服务相关的程序集:

名称 说明
System.DirectoryServices 利用System.DirectoryServices命名空间,可以方便地从托管代码中访问AD域服务。 该命名空间包含两个组件类,即DirectoryEntry和DirectorySearcher,它们使用AD服务接口 (ADSI) 技术。 ADSI是Microsoft 提供的一组接口,作为使用各种网络提供程序的灵活的工具。 无论网络有多大,ADSI 都可以使管理员能够相对容易地定位和管理网络上的资源。
System.DirectoryServices.AccountManagement 命名空间提供了统一的访问和用户操作、计算机和组安全原则(在多个主要存储):活动目录域服务 (AD DS)、 活动目录轻量级目录服务 (AD LDS)和机器 SAM (MSAM)。 管理独立于 命名空间的目录对象。
System.DirectoryServices.ActiveDirectory 命名空间提供一个围绕Microsoft AD服务任务构建的高级别抽象对象模型。AD服务概念(例如,林、域、站点、子网、分区和架构)是此对象模型的一部分。
System.DirectoryServices.Protocols 命名空间提供在轻量目录访问协议 (LDAP) 3 版 (V3) 和目录服务标记语言 (DSML) 2.0 版 (V2) 标准中定义的方法。

两种方法的实现与比较

为了获得用户的目录信息,看来我们需要使用的是前两个程序集和名称空间。

使用System.DirectoryServices.AccountManagement获取用户信息示例:

public DirectoryEntry GetEntryByUsername(string username)
{
    PrincipalContext ctx = new PrincipalContext(ContextType.Domain, domain);
    UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);
    DirectoryEntry entry = user.GetUnderlyingObject() as DirectoryEntry;
    
    return entry;
}

第一次运行花费时间630ms

还有一种方法是直接使用目录搜索

public SearchResult GetEntryByUsername(string username)
{
    DirectorySearcher search = new DirectorySearcher();
    search.Filter = $"(&(objectClass=user)(sAMAccountName={username}))";
    SearchResult result = search.FindOne();
}

第一次运行花费时间355ms

而且后续处理的事件花费差异也很大,使用DirectoryEntry获得的对象,所有属性还需要按其结构进行遍历:

public static void ShowProperties(DirectoryEntry entry)
{
    PropertyCollection props = entry.Properties;
    foreach (string k in props.PropertyNames)
    {
        Console.WriteLine("{0}: {1}", k, props[k].Value);
        if (props[k].Value is Array)
        {
            Array arr = (Array)props[k].Value;
            foreach (object obj in arr)
            {
                Console.WriteLine("    Item: " + obj + "    Type: " + obj.GetType().Name);
            }
       }
    }
}

而通过DirectorySearcher查询,不但查询速度快,结果似乎也是直接缓存中读出来的,高效快速。

if (result != null)
{
    // user exists, cycle through LDAP fields (cn, telephonenumber etc.)  
    ResultPropertyCollection fields = result.Properties;
    foreach (String ldapField in fields.PropertyNames)
    {
        // cycle through objects in each field e.g. group membership  
        // (for many fields there will only be one object such as name)  
        foreach (Object myCollection in fields[ldapField])
            Console.WriteLine(String.Format("{0,-20} : {1}",
                          ldapField, myCollection.ToString()));
    }
}

所以这里推荐使用DirectorySearcher直接进行目录对象(不仅限于用户,还有组织单元、计算机、其它设备等信息)的搜索和详细信息输出,效率会提升不少。

用途

利用Microsoft目录服务管理的公司,可以通过目录属性进行网络、设备等进行基于角色的访问控制,通过不同的AD组或设置目录属性,采用不同的管理策略。而IT经常需要对此过程进行自动化处理,所以通过LDAP进行目录服务数据的更改和访问就必不可少,还可以自动化权限(AD组、属性)的复查流程,减少组织和企业管理的人工成本。

posted @ 2022-03-30 22:10  桁椽  阅读(1024)  评论(0编辑  收藏  举报