Click here to Skip to main content
Click here to Skip to main content

An RFC 2253 Compliant Distinguished Name Parser

, 27 Mar 2009
Rate this:
Please Sign up or sign in to vote.
A set of classes to parse and manipulate LDAP distinguished names
Sample Image - DNParser.png

Introduction

Every object in an LDAP directory is uniquely identified by a distinguished name (DN). A distinguished name specifies the name of the object itself, along with the names of all its parent objects. Thus, a DN identifies the object itself as well as its position in the tree.

The rules for representing distinguished names as strings are laid out in RFC 2253, and they actually get a little complex in places. Hence, this parser.

Background

I was rewriting some terrible ADSI code (that I wrote myself a few years ago, but I'm going to gloss over that little detail), and I noticed that the original code navigated the LDAP tree by getting an ADSI object, reading its distinguishedName property, then getting its parent object and reading that object's distinguishedName property recursively. That procedure made me pretty uncomfortable because it involved a lot of back-and-forth with the server that wasn't really necessary. I figured it would be a simple thing to parse a distinguished name in code, thereby avoiding all the server-side processing. Well, it turns out that it was less simple than I expected, but it came out pretty well, so I thought I'd share the results with you folks.

Using the code

There are three main classes in this code:

  • DN, which represents a full distinguished name
  • RDN, which represents a relative distinguished name
  • RDNComponent, which represents the individual components of a multivalued RDN

I don't think that multivalued RDNs are even supported by Active Directory, but they're supported by the RFC, so they're supported by my parser.

You construct a DN object by feeding it a distinguished name string, like so:

DN myDN = new DN(@"CN=Pete Everett\, esq.,OU=People,DC=example,DC=com");

To print out a DN object, you use its ToString() method, as you'd expect.

Console.WriteLine(myDN.ToString());
// prints out:
// CN=Pete Everett\, esq.,OU=People,DC=example,DC=com

But if you'd like more control over the formatting, you can specify categories of characters to escape.

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.)

To get the parent object of a given DN object, you can use its Parent property.

DN myParentDN = myDN.Parent;
Console.WriteLine(myParentDN.ToString());
// prints out:
// OU=People,DC=example,DC=com

And to get a child of a given DN object, you can use its GetChild() method.

DN myChildDN = myParentDN.GetChild("CN=Mike");
Console.WriteLine(myChildDN.ToString());
// prints out:
// CN=Mike,OU=Poeple,DC=example,DC=com

You can also access the individual RDNs of a given DN object, like so:

Console.WriteLine(myChildDN.RDNs[2].ToString());
// prints out:
// DC=example

And you can get the type or value of a component of an RDN, if you're inclined.

Console.WriteLine(myChildDN.RDNs[1].Components[0].ComponentValue);
// prints out:
// People

Design Considerations

I wanted to make sure that each DN (and its component parts) was immutable. This allowed me to do a couple of cute things up front, like calculate an object's hash code upon object creation (and use the hash code as a quick test for inequality) and pass references to the same underlying objects between different DN objects. For example:

// 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;

It's worth noting, though, that this only does the job halfway, because:

// 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");

Limitations

  • This is my first crack at coding something to match an RFC. I think I've done a pretty good job of it, but it's possible that I've misinterpreted something in the spec. Send criticisms my way. (But be gentle. I'm a little sensitive.)
  • Working with multibyte characters is tricky. The RFC specifies that multibyte characters should be allowed to be escaped as their individual bytes. So for example, Unicode character 0x266B (a musical note) should be allowed to be represented as \E2\99\AB (its three-byte UTF-8 encoding). The problem is that ADSI's GetObject() method (and anything built on top of it, like .NET's DirectoryServices stuff) doesn't support escaped multibyte characters. So if you feed it an escaped character, it'll choke. But if you feed an unescaped multibyte character to something that expects ASCII, it'll also choke. My workaround to this problem has been to let you choose which categories of characters to escape. (There's an example above.)
  • I thought up as many strange test cases as I could and wrote a bunch of NUnit tests which kept me company throughout the development process. I've included the tests along with the code, so you can verify that any changes you might want to make won't break existing functionality. I'm sure, though, that I've done a half-hearted job of thinking of tests, and if you see any glaring omissions, please send them my way.

History

  • March 7, 2005 - Initial posting
  • March 26, 2009 - Fixed some null-reference bugs

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Pete Everett
Software Developer (Senior)
United States United States
Pete has just recently become a corporate sell-out, working for a wholly-owned subsidiary of "The Man". He counter-balances his soul-crushing professional life by practicing circus acrobatics and watching Phineas and Ferb reruns. Ducky Momo is his friend.

Comments and Discussions

 
QuestionInternal .NET Utility class can be called using reflection Pinmembergbrayut29-Apr-14 7:04 
QuestionError parsing Distinguished Names with a comma [modified] PinmemberJeremy Hutchins3-Oct-13 9:50 
QuestionGithub and updates PinmemberMember 95767538-Nov-12 9:19 
QuestionRFC compliance and .Net PinmemberAlan Seedhouse16-Apr-12 23:49 
Came across you excellent article/code which explains a lot about the DN format. In one of my own apps I had a problem with special chars which I was not aware of at the time...DNs are much more complex than they appear. I have been experimenting with various DN formats. The DirectoryEntry class in .Net does not appear to support AttributeValues using the hexstring format (e.g. #04024141). I assume the DirectoryEntry class is not fully RFC compliant but if you enter this in the properties dialog in ADUC (Attribute Editor) it works and is converted to the appropriate text.
 
Also a DN should be represented as UTF8 but c# strings internally are UTF16 where does it get converted and do I need to be concerned.
GeneralUnable to Parse names with / PinmemberCoderGirl4225-Mar-09 13:42 
AnswerRe: Unable to Parse names with / PinmemberPete Everett26-Mar-09 8:10 
QuestionBug? PinmemberCoderGirl4218-Mar-09 9:17 
AnswerRe: Bug? PinmemberPete Everett26-Mar-09 5:18 
AnswerRe: Bug? PinmemberPete Everett27-Mar-09 10:12 
GeneralGood work! [modified] PinmemberCoderGirl4214-Mar-09 10:11 
QuestionPermission to ingegrate in another project Pinmemberrroman8115-Dec-08 20:10 
AnswerRe: Permission to ingegrate in another project PinmemberPete Everett17-Dec-08 1:21 
GeneralRe: Permission to ingegrate in another project Pinmemberrroman8117-Dec-08 7:38 
GeneralYou rock! PinmemberMikeonn15-Nov-06 0:57 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140709.1 | Last Updated 27 Mar 2009
Article Copyright 2005 by Pete Everett
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid