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

Active Directory Object Navigator

, 25 Apr 2005
Rate this:
Please Sign up or sign in to vote.
An article describing how to connect to an Active Directory database.

Application Image

Introduction

First of all, I want to introduce you to the problem that led me to this solution. I needed to authenticate against the Active Directory (AD) database, but found no object oriented way to do so. I found myself in a dead-end. How to use the Active Directory tree of objects in a way that didn't go against our 3-tier object oriented architecture.

So I decided I had to abstract the whole AD layer usage of my application. And to do so, I needed a framework that would allow me to navigate through AD objects as if they were an XML file (rough comparison I know!!!).

Background

I found out so many articles on how to get this property on AD, or how to get that property, but none really teaching how to use the LDAP language for instance. So I had a tough time trying to figure out how to reach an object via LDAP query.

Let me say that I do not intend to build an AD manager, and in my AD Object Navigator, I don't even allow you to change properties (although you could with the OriginalDirectoryEntry property).

My intention is to give you (the reader) a basic knowledge of how to use the AD database and a built framework for getting users, groups, containers and organizational units if you, like me, are planning on authenticating against an Active Directory database (and planning on using the AD user as the user for your application).

Using the code

I included with the source code (inside the Doc\ directory) a Windows HTML Help that explains on detail every class and function in the framework.

I commented the properties in the LoadUser function so it would load faster, but if you need more info about your users, just uncomment it or add other properties to it. Please let me know if it helped you and what you added.

The LoadUser method:

//C#
u = new Objects.User();
u.Id = de.NativeGuid;
u.UserName = getStringProperty(de.Properties,"sAMAccountName");
u.Email = getStringProperty(de.Properties,"userPrincipalName");
//u.GivenName = getStringProperty(de.Properties,"givenName");
u.OriginalDirectoryEntry = de;
if (de.Properties["useraccountcontrol"].Value != null)
{
    if (((int)de.Properties["useraccountcontrol"].Value & 2) == 0)
    {
        u.Enabled = true;
    }
    else
    {
        u.Enabled = false;
    }
}
else
{
    u.Enabled = false;
}
//u.AdditionalPhoneNumbers = 
//             getStringArrayProperty(de.Properties,"otherTelephone");
//u.AdditionalHomePages = getStringArrayProperty(de.Properties,"url");
//u.City = getStringProperty(de.Properties,"l");
//u.Country = getStringProperty(de.Properties,"c");
//u.Description = getStringProperty(de.Properties,"description");
u.DisplayName = getStringProperty(de.Properties,"displayName");
//u.HomePage = getStringProperty(de.Properties,"wWWHomePage");
//u.Initials = getStringProperty(de.Properties,"initials");
//u.PhysicalDeliveryOfficeName = 
//     getStringProperty(de.Properties,"physicalDeliveryOfficeName");
//u.PostOfficeBox = getStringProperty(de.Properties,"postOfficeBox");
//u.State = getStringProperty(de.Properties,"st");
//u.StreetAddress = getStringProperty(de.Properties,"streetAddress");
//u.TelephoneNumber = getStringProperty(de.Properties,"telephoneNumber");

The other thing you should know is that (for ease of use) I added three constants to the framework: DEFAULTDOMAIN, DEFAULTUSERNAME, DEFAULTPASSWORD. These constants are to be used with the framework functions so you won't have to pass them as parameters. Although they are used as the impersonate data, they could be set to nothing (I wouldn't recommend it though!). These constants are in the ADManager class.

#region Constants
    const string DEFAULTDOMAIN = "yourDomain";
    const string DEFAULTUSERNAME = "yourUserName";
    const string DEFAULTPASSWORD = "yourPassword";
#endregion

I'll explain the most common situations where you would like to be using this framework:

Authenticating an user against Active Directory:

'VB.NET
Public Function ValidateUser(ByVal username as _
          string, ByVal password as string) as boolean
  Dim u as BVA.ActiveDirectory.Navigator.Objects.User = _
     BVA.ActiveDirectory.Navigator.Business.AdManager.GetUser(username,password)
  return (u is nothing)
End Function
//C#
public bool ValidateUser(string username, string password)
{
  BVA.ActiveDirectory.Navigator.Objects.User u = 
    BVA.ActiveDirectory.Navigator.Business.AdManager.GetUser(username,password);
  return (u==null);
}

Getting the groups that an user is a member of:

'VB.NET
Public Function MemberShips(ByVal username as string, _
      ByVal password as string) as _
      BVA.ActiveDirectory.Navigator.Objects.GroupCollection
  Dim u as BVA.ActiveDirectory.Navigator.Objects.User = _
    BVA.ActiveDirectory.Navigator.Business.AdManager.GetUser(username,password)
  return u.MemberOf
End Function
//C#
public BVA.ActiveDirectory.Navigator.Objects.GroupCollection 
                MemberShips(string username, string password)
{
  BVA.ActiveDirectory.Navigator.Objects.User u =
    BVA.ActiveDirectory.Navigator.Business.AdManager.GetUser(username,password);
  return (u.MemberOf);
}

Getting the users in a determined group:

(SID is a unique ID that every AD object has in the AD database.)

'VB.NET
Public Function Members(ByVal SID as String) as _
          BVA.ActiveDirectory.Navigator.Objects.UserCollection
  Dim g as BVA.ActiveDirectory.Navigator.Objects.Group = _
    BVA.ActiveDirectory.Navigator.Business.AdManager.GetGroup(SID)
  return g.Members
End Function
//C#
public BVA.ActiveDirectory.Navigator.Objects.GroupCollection 
                                          Members(string SID)
{
  BVA.ActiveDirectory.Navigator.Objects.Group g = 
     BVA.ActiveDirectory.Navigator.Business.AdManager.GetGroup(SID)
  return (g.Members);
}

And there are many more applications for this framework like getting all users in the domain, checking to see if a user account is enabled, retrieving all the users in a determined organizational unit, and many more. Explore the code.

I have provided a demo application that shows the entire Active Directory tree.

Points of Interest

One thing that is really great about this framework is that it is completely loaded on-demand.

This means that all collections are loaded only when you need them. This is great because the Active Directory database isn't really fast, so you really wouldn't want to load the entire tree every time you want to access a user, for instance.

I.e.: let's say you have an Organizational Unit Users and then inside it you have an Organizational Unit Support and inside Support you have user TestUser. When you get the root node, it doesn't load the Users Organizational Unit. It only loads it when you access root.OrganizationalUnits. Then it loads all child nodes for the root node (including our Users node). Then when you access UsersNode.OrganizationalUnits, it loads all child nodes for the Users Organizational Unit node (including our Support node). And so on.

Another thing that would really add to this framework (and I didn't have the time to implement it, even though I would like to do it a lot) is adding caching to it, so when you get one node you already got before, it would use the cached version.

History

V 1.0 - AD Object Navigator released.

To-Do's

Caching the objects in the framework.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

bernardoh
Web Developer
United Kingdom United Kingdom
Bernardo Heynemann is a senior developer at ThoughtWorks UK in London. He is really into Visual Studio 2008, LINQ and ASP.Net MVC. He's also chairman of Stormwind Project (http://www.stormwindproject.org). He can be found at his blog at http://blogs.manicprogrammer.com/heynemann.

Comments and Discussions

 
GeneralGreat work ! PinmemberAdnan S Hussain18-Oct-08 23:11 
GeneralProblem converting project for VS 2005/2008 Pinmembertsudonymn9-Oct-08 10:53 
GeneralRe: Problem converting project for VS 2005/2008 PinmemberMember 244544913-Jan-09 18:56 
QuestionHow to assign a user into OU PinmemberHakmeh Mohannad18-Apr-08 22:28 
GeneralGUID vs SID Pinmembermkeysaer11-Jan-07 6:30 
QuestionHow to read Contacts from an OU? PinmemberPaulo Vaz2-Jan-07 0:18 
AnswerRe: How to read Contacts from an OU? Pinmemberbernardoh2-Jan-07 0:45 
AnswerRe: How to read Contacts from an OU? [modified] Pinmembermkeysaer12-Jan-07 9:47 
GeneralRe: How to read Contacts from an OU? PinmemberPaulo Vaz13-Jan-07 6:39 
GeneralGetGroup is not there PinmemberJos Branders30-Dec-06 7:40 
GeneralRe: GetGroup is not there Pinmemberbernardoh2-Jan-07 0:43 
GeneralThanks Pinmemberbanka_ravi6-Dec-06 0:30 
GeneralActive directory on web PinmemberMirko2C29-Nov-06 6:44 
GeneralRe: Active directory on web Pinmemberbernardoh29-Nov-06 6:54 
GeneralRe: Active directory on web Pinmemberthietnt29-May-08 16:12 
GeneralServer is not Operational Pinmembershubie3-Sep-06 15:32 
GeneralRe: Server is not Operational Pinmembernjdnjdnjdnjdnjd24-Oct-06 8:54 
GeneralRe: Server is not Operational PinmemberJocaover3-Jul-08 22:02 
QuestionGetUser without their password PinmemberdwclarkNU26-Jun-06 7:43 
AnswerRe: GetUser without their password PinmemberDungVinh15-Aug-06 21:54 
Questionhow to retrieve user groups PinmemberKrispyKreme22-Jun-06 10:18 
AnswerRe: how to retrieve user groups Pinmemberbernardoh22-Jun-06 18:32 
GeneralRe: how to retrieve user groups Pinmemberbernardoh22-Jun-06 18:35 
Generalcode reusage PinmemberKrispyKreme22-Jun-06 9:32 
GeneralRe: code reusage Pinmemberbernardoh22-Jun-06 18:29 
GeneralAD Development Sandbox Pinmembergk28-May-06 17:52 
GeneralIssue with AdManager.cs PinmemberMitzs3-Apr-06 3:30 
GeneralRe: Issue with AdManager.cs Pinmemberbernardoh3-Apr-06 4:21 
GeneralRe: Issue with AdManager.cs PinmemberMitzs3-Apr-06 5:40 
QuestionCan I access LDAP of Solaris environment from my Windows environment ?? PinmemberSuranjan Nandi8-Mar-06 4:06 
QuestionA question if you don't mind? - Trusted Domains PinmemberDace15-Feb-06 4:00 
AnswerRe: A question if you don't mind? - Trusted Domains PinmemberDace16-Feb-06 1:48 
Generalan invalid dn syntax has been specified Pinmemberjwc jwc31-Jan-06 11:05 
GeneralRe: an invalid dn syntax has been specified Pinmemberbernardoh1-Feb-06 12:09 
GeneralRe: an invalid dn syntax has been specified PinmemberPreky17-May-06 23:02 
QuestionObject reference is not set to an instance of an Object using AD Pinmemberdasrimk7-Dec-05 18:15 
AnswerRe: Object reference is not set to an instance of an Object using AD Pinmemberbernardoh8-Dec-05 5:55 
AnswerRe: Object reference is not set to an instance of an Object using AD PinmemberAlegreBonifacio13-Jan-06 5:12 
QuestionADAM Pinmembernarayankverma15-Nov-05 15:40 
GeneralGroup with in a Group Pinmemberdtaylor73011-Oct-05 10:36 
GeneralRe: Group with in a Group Pinmemberbernardoh8-Dec-05 5:53 
QuestionHelp file setup Pinmemberesteban40426-Sep-05 4:33 
AnswerRe: Help file setup Pinmemberbernardoh26-Sep-05 6:57 
GeneralRe: Help file setup Pinmemberesteban40426-Sep-05 7:39 
QuestionHow to list available methods of AD objects PinsussArthur Christoph10-Aug-05 10:06 
AnswerRe: How to list available methods of AD objects Pinmemberbernardoh10-Aug-05 10:40 
Generaladd, delete, setpassword, etc... Pinmembercloudno922-Jul-05 17:12 
GeneralRe: add, delete, setpassword, etc... Pinmemberbernardoh25-Jul-05 3:46 
Generaldefining domainname, username, password as constant Pinmembercloudno921-Jul-05 17:26 
GeneralRe: defining domainname, username, password as constant Pinmemberbernardoh22-Jul-05 3:23 

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.140827.1 | Last Updated 26 Apr 2005
Article Copyright 2005 by bernardoh
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid