符合 RFC 2253 的专有名称解析器






4.87/5 (9投票s)
一组用于解析和操作 LDAP 专有名称的类

引言
LDAP 目录中的每个对象都由一个可分辨名称 (DN
) 唯一标识。 可分辨名称指定对象本身的名称以及所有其父对象的名称。 因此,DN
标识对象本身及其在树中的位置。
以字符串形式表示可分辨名称的规则在 RFC 2253 中进行了说明,并且在某些地方实际上变得有点复杂。 因此,这就是此解析器的作用。
背景
我正在重写一些糟糕的 ADSI 代码(几年前我自己编写的,但我会忽略这个小细节),并且我注意到原始代码通过获取一个 ADSI
对象、读取其 distinguishedName
属性,然后获取其父对象并递归地读取该对象的 distinguishedName
属性来导航 LDAP 树。 该过程让我感到非常不舒服,因为它涉及很多与服务器之间的来回交互,而这些交互实际上并没有必要。 我认为用代码解析可分辨名称是一件简单的事情,从而避免所有服务器端处理。 好吧,事实证明它比我预期的要复杂一些,但是结果还不错,所以我认为我会与大家分享结果。
使用代码
此代码中有三个主要类
DN
,表示完整的可分辨名称RDN
,表示相对可分辨名称RDNComponent
,表示多值RDN
的各个组件
我认为 Active Directory 甚至不支持多值 RDN
,但 RFC 支持它们,因此我的解析器也支持它们。
通过向其提供可分辨名称 string
来构造一个 DN
对象,如下所示
DN myDN = new DN(@"CN=Pete Everett\, esq.,OU=People,DC=example,DC=com");
要打印出一个 DN
对象,您可以像预期的那样使用其 ToString()
方法。
Console.WriteLine(myDN.ToString());
// prints out:
// CN=Pete Everett\, esq.,OU=People,DC=example,DC=com
但是,如果您想更好地控制格式,则可以指定要转义的字符类别。
Console.WriteLine(myDN.ToString(EscapeChars.None));
// prints out:
// CN=Pete Everett, esq.,OU=People,DC=example,DC=com
// (Note that this is an incorrect DN format, and will not parse correctly.)
要获取给定 DN
对象的父对象,可以使用其 Parent
属性。
DN myParentDN = myDN.Parent;
Console.WriteLine(myParentDN.ToString());
// prints out:
// OU=People,DC=example,DC=com
要获取给定 DN
对象的子对象,可以使用其 GetChild()
方法。
DN myChildDN = myParentDN.GetChild("CN=Mike");
Console.WriteLine(myChildDN.ToString());
// prints out:
// CN=Mike,OU=Poeple,DC=example,DC=com
您还可以访问给定 DN
对象的各个 RDN
,如下所示
Console.WriteLine(myChildDN.RDNs[2].ToString());
// prints out:
// DC=example
如果您愿意,可以获取 RDN
组件的类型或值。
Console.WriteLine(myChildDN.RDNs[1].Components[0].ComponentValue);
// prints out:
// People
设计考虑因素
我想确保每个 DN
(及其组成部分)都是不可变的。 这使我可以预先做一些可爱的事情,例如在对象创建时计算对象的哈希码(并将哈希码用作快速的不等式测试),并在不同的 DN
对象之间传递对相同底层对象的引用。 例如
// referenceDN contains references to 4 RDN objects
DN referenceDN = new DN("OU=Marketing,OU=People,DC=example,DC=com");
// parentDN contains references to 3 of the same RDN objects from referenceDN
DN parentDN = referenceDN.Parent;
但是,值得注意的是,这只完成了一半的工作,因为
// childDN is now equal to referenceDN, but its first RDN points to a
// different object than referenceDN's first RDN does.
DN childDN = parentDN.GetChild("OU=Marketing");
限制
- 这是我第一次编写符合 RFC 的代码。 我认为我做得很好,但我可能误解了规范中的某些内容。 请向我发送批评意见。(但请温柔一点。我有点敏感。)
- 使用多字节字符很棘手。 RFC 规定应该允许将多字节字符转义为其各个字节。 因此,例如,Unicode 字符 0x266B(音符)应该允许表示为 \E2\99\AB(其三字节 UTF-8 编码)。 问题是 ADSI 的
GetObject()
方法(以及建立在其之上的任何方法,例如 .NET 的 DirectoryServices stuff)不支持转义的多字节字符。 因此,如果您向其提供转义的字符,它会崩溃。 但是,如果您向期望 ASCII 的东西提供未转义的多字节字符,它也会崩溃。 我解决此问题的方法是让您选择要转义的字符类别。(上面有一个例子。) - 我想出了尽可能多的奇怪测试用例,并编写了一堆 NUnit 测试,这些测试在整个开发过程中陪伴着我。 我已将测试与代码一起包含在内,因此您可以验证您可能要进行的任何更改都不会破坏现有功能。 但是,我确信我在考虑测试方面做了一半的工作,如果您发现任何明显的遗漏,请发送给我。
历史
- 2005 年 3 月 7 日 - 首次发布
- 2009 年 3 月 26 日 - 修复了一些
null
引用错误