65.9K
CodeProject 正在变化。 阅读更多。
Home

.NET Client Classes for openldap/winldap

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (15投票s)

2003 年 3 月 12 日

CPOL

5分钟阅读

viewsIcon

251450

downloadIcon

2252

一个使用 LDAP/OpenLDAP 的 .Net 示例

LDAP - 轻量级目录访问协议

环境

客户端 服务器
openldap (明文|tls) openldap
winldap (明文|tls) openldap
openldap (明文|tls) Active Directory
winldap (明文|tls) Active Directory

注意: 在使用该库之前,您需要仔细检查代码。

构建 openldap 客户端库

以下是在 Windows 上构建 openldap 的步骤。要构建客户端库,不需要太多调整。我使用的是 openldap-2.1.12。 .dsp 和 .dsw 文件位于 ..\build\ 目录下。如果打开 main.dsw,它包含了 openldap 服务器以及 ldap 客户端库。对于客户端,您需要构建 libldap_rliblber 项目。我没有使用 SASL 身份验证机制,因此我从 ldap 库中删除了 SASL 和 Regex 的依赖项(尽管,添加 sasl/regex 支持并不难)。要删除 SASL/Regex 依赖项,请展开 setup 项目。打开 portable.nt 文件并注释掉

//#define HAVE_REGEX_H 1
//#define HAVE_CYRUS_SASL 1

(或者参考 此处的说明 。)

右键单击 libldap_r (线程安全版本) 和 liblber 项目,然后重新生成。这应该可以成功构建。现在,您需要为 VS.NET 设置库搜索目录,指向输出的 oldap_r.libolber32.lib 的位置。对于头文件也一样。

..\openldap-2.1.12\Debug..\openldap-2.1.12\Release 或某个通用目录,或者重命名 debug 和 release 文件。
..\openldap-2.1.12\include

为测试目的在 Windows 上构建 openldap 服务器

请参考 此处的构建说明,这适用于 openldap-2.0.xx 版本。

您也可以成功构建 openldap-2.1.xx,我使用的是 Sleepycat Berkley 的 db-4.1.xx 和 cyrus-sasl-1.5.xx。一切构建完成后,您需要将 *.exe 和 *.dll 文件复制到某个目录,该目录将作为 openldap 服务器的基础目录。

您需要将 schema 目录从 ..\openldap\openldap-2.1.12\servers\slapd\schema 复制到您的 openldap 基础目录,并将示例 slapd.conf 文件从 ..\openldap\openldap-2.1.12\servers\slapd\slapd.conf 复制过来。

在 slapd.conf 中,在任何 include 语句之前添加 ucdata-path。如下所示:

ucdata-path "X:/openldap-2.1.12/ucgendat". 

然后打开命令提示符并运行:

ucgendat.exe -o X:/openldap-2.1.12/ucgendat

如果出现此错误: error loading ucdata (error -127),您就知道 ucgendata 没有正确设置。在 2.0.xx 版本中,这并不是必需的。

根据您的需求填写/修改 slapd.conf 的其余部分。请查阅各种资源,特别是 slapd.conf 的 man 页,位于 http://www.openldap.org/software/man.cgi,然后输入 slapd.conf,还可以查看 快速入门指南管理员指南

为了调试可能的错误,您可以运行 slapd -d 255。要做到这一点,您需要使用 LDAP_DEBUG 进行编译。这可以在 portable.nt 文件中添加,它位于 setup 项目下;在顶部附近添加:

#define LDAP_DEBUG 1

如果您想添加 ssl/tls 支持,可以通过 openssl 实现。您需要获取最新的 openssl 版本(例如 openssl-0.9.7a),并按照随包提供的 INSTALL.W32 文件中的说明进行操作。构建 openssl 为 dll 或静态库后,您需要将其 .lib/.h 目录添加到 VS.NET 的库/头文件搜索目录中。现在,您需要从 openldap 解决方案的 setup 项目中打开 portable.nt。在顶部附近添加此内容:

#define HAVE_TLS 1 
#define HAVE_OPENSSL_SSL_H 1 
#pragma comment(lib, "ssleay32r.lib") 
#pragma comment(lib, "libeay32r.lib")

然后构建 openldap。现在您需要编辑 slapd.conf 文件。相关的选项有:TLSVerifyClient, TLSCertificateFile, TLSCertificateKeyFile, TLSCACertificateFile, TLSCipherSuite 等。

现在您可以启动 ldap 来监听 ssl/tls 连接了。

slapd -h "ldaps://somehost ldap://somehost

虽然使用 ldap_start_tls_s 时不需要 ldaps://,因为它在普通的 ldap 端口 (389) 上通信,而不是在 ssl 的 636 端口上。当使用 winldap 客户端连接时,服务器证书的 CA 必须被客户端 PC 信任,这意味着它必须安装在受信任的 CA 下。您可以通过使用 Internet Explorer 连接到服务器来检查服务器证书是否存在任何问题。有关 winldap 的更多故障排除信息,请在 groups.google.com 中搜索:ldap_sslinit 故障排除组:microsoft.public.platformsdk.active.directory,您可以在那里找到 mskb 文章。

Ldap .NET 类用法

Connection

LdapClient c = new  LdapClient("127.0.0.1", 
               LdapClient.DefaultPort,true /*version 3?*/, true /*use tls?*/);
c.ldap_simple_bind_s("bind_dn", "your_pass");

搜索

LdapResult res;
int count = c.ldap_search_ext_s("dn_to_start_the_search_at", 
              LDAPSearchScope.LDAPSCOPE_SUBTREE,
              "sn=*",         /* search filter */
              new string[0],  /* attribs to return, empty for all */
              false,          /* return attrsonly? */
              60,             /* allow 60 secs for the search */
              0,              /* 0 == no size limit on returned entries */
              out res);

Console.WriteLine("Search Returned: {0}", count);

foreach(Oldap.LdapEntry entry in res)
{
    Console.WriteLine("dn:{0}", entry.DN);
    foreach(Oldap.LdapAttribute attr in entry)
    {
        if(attr.Name == "string_type?")
            foreach(string val in attr.StringValues)
                Console.WriteLine("{0}: {1}", attr.Name, val);
        else if(attr.Name == "binary_type?")
            foreach(Byte[] val in attr.BinaryValues)
            {
                mem = new MemoryStream();
                mem.Write(val, 0, val.Length);
                //do something with it
            }
    }
    Console.WriteLine();
}

添加新条目

(支持的类型:String 或 String[],Byte[] 或 Byte[] 数组)

string entryDN = "dn_of_new_entry";
ListDictionary attrval = new ListDictionary();
attrval["objectClass"]=new string[]{"top", "person"}; 
//person class is abstract in AD
attrval["cn"]=new string[]{"test"};
attrval["sn"]="test";

//Byte[] example. To add multiple binary values you have 
//to pass array of byte[], so something like
//ArrayList that has Added byte[]s and then gives the array 
//with ToArray method should work
//Bitmap bmp = new Bitmap("..\\..\\some.bmp"); 
//mem = new MemoryStream();  
//bmp.Save(mem, ImageFormat.Bmp);
//attrval["personPhoto"]= new object[]{mem.ToArray()}; //aray of byte[]     
//or
//attrval["personPhoto"]= mem.ToArray(); //byte[] 
//personPhoto is custom attribute with 
//SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 
//in AD it's 2.5.5.10 
//To support it i defined a new objectClass 
//that includes it, and "person" objectClass
//used in above example doesn't know about it.

c.ldap_add_s(entryDN, attrval);

if(c.ldap_compare_s(entryDN, "cn", "test") == true) 
//check if value exists for attrib under specific entry

替换现有条目中的属性

attrval["sn"]="test_modified";
c.ldap_mod_replace(entryDN, attrval);

向现有条目添加属性

attrval["telephoneNumber"]=new string[]{"phone1","phone2"};
c.ldap_mod_add(entryDN, attrval);

删除现有条目中的属性

attrval["telephoneNumber"]=new string[0];          
//remove attribute completely
attrval["telephoneNumber"]=new string[]{"phone2"}; 
//remove specific value from attribute                                                
//or whole attribute if it's the only value

c.ldap_mod_delete(entryDN, attrval);

删除整个条目

c.ldap_delete_s(entryDN);

抛出异常

LDAPException
LDAPExceptionPartialResult - thrown when searching and specifying size limit. 
partial_count data member has the returned count.
InvalidCastException

其余的 ldap 函数,包括异步方法、引用(LDAP_OPT_REFERRALS)等……将根据需要添加。

参考

Winldap 相关

Winldap 常见的 SSL 错误
0x80090322 - "目标主体名称不正确"
0x80090325 - "证书链由不受信任的颁发机构颁发"

Active Directory 相关

免责声明:此代码和信息“按原样”提供,不提供任何形式的明示或暗示保证,包括但不限于适销性和/或适用于特定用途的暗示保证。
© . All rights reserved.