Programming Active Directory


To develop programs for Active Directory, you can either use the classes from the System.Directory Services or the System.DirectoryServices.Protocols namespaces. In the namespace System. DirectoryServices you can find classes that wrap Active Directory Service Interfaces (ADSI) COM objects to access the Active Directory.

ADSI is a programmatic interface to directory services. It defines some COM interfaces that are implemented by ADSI providers. This means that the client can use different directory services with the same programmatic interfaces. The .NET Framework classes in the System.DirectoryServices namespace make use of ADSI.

Figure 22-8 shows some ADSI Providers (LDAP, WinNT, and NDS) that implement COM interfaces such as IADs and IUnknown. The assembly System.DirectoryServices makes use of the ADSI providers.

image from book
Figure 22-8

Classes from the namespace System.DirectoryServices.Protocols make use of Directory Services Markup Language (DSML) Services for Windows. With DSML, standardized Web service interfaces are defined by the OASIS group (http://www.oasis-open.org/committees/dsml).

To use the classes from the System.DirectoryServices namespace, you have to reference the System.DirectoryServices assembly. With the classes in this assembly you can query objects, view and update properties, search for objects, and move objects to other container objects. In the code segments that follow a little later in this section, you use a simple C# console application that demonstrates the functionality of the classes in the System.DirectoryServices namespace.

This section covers the following:

  • Classes in the System.DirectoryServices namespace

  • The process of connecting to the Active Directory (binding)

  • Getting directory entries and creating new objects and updating existing entries

  • Searching Active Directory

Classes in System.DirectoryServices

The following table shows the major classes in the System.DirectoryServices namespace.

Class

Description

DirectoryEntry

This class is the main class of the System.DirectoryServices namespace. An object of this class represents an object in the Active Directory store. This class is used to bind to an object and to view and to update properties. The properties of the object are represented in a PropertyCollection. Every item in the PropertyCollection has a PropertyValueCollection.

DirectoryEntries

DirectoryEntries is a collection of DirectoryEntry objects. The Children property of a DirectoryEntry object returns a list of objects in a DirectoryEntries collection.

DirectorySearcher

This class is the main class used for searching for objects with specific attributes. To define the search the SortOption class and the enumer- ations SearchScope, SortDirection, and ReferalChasingOption can be used. The search results in a SearchResult or a Search ResultCollection. You also get ResultPropertyCollection and ResultPropertyValueCollection objects.

Binding

To get the values of an object in Active Directory, you have to connect to the Active Directory service. This connecting process is called binding. The binding path can look like this:

LDAP://dc01.thinktecture.com/OU=Development, DC=Thinktecture, DC=Com

With the binding process, you can specify these items:

  • The protocol specifies the provider to be used

  • The server name of the domain controller

  • The port number of the server process

  • The distinguished name of the object; this identifies the object you want to access

  • The username and password, if the user who is allowed to access the Active Directory is different from the current logged-on user

  • An authentication type can also be specified if encryption is needed

The following subsections discuss these options in more detail.

Protocol

The first part of a binding path specifies the ADSI provider. The provider is implemented as a COM server; for identification a progID can be found in the registry directly under HKEY_CLASSES_ROOT. The providers that are available with Windows XP are listed in the following table.

Provider

Description

LDAP

LDAP Server, such as the Exchange directory and Windows 2000 Server or Windows Server 2003 Active Directory Server.

GC

GC is used to access the global catalog in Active Directory. It can be used for fast queries.

IIS

With the ADSI provider for IIS it's possible to create new Web sites and to administer them in the IIS catalog.

WinNT

To access the user database of old Windows NT 4 domains you can use the ADSI provider for WinNT. The fact that NT 4 users only have a few attributes remains unchanged. It is also possible to use this protocol to bind to a Windows 2000 domain, but here you are also restricted to the attributes available with NT 4.

NDS

This progid is used to communicate with Novell Directory Services.

NWCOMPAT

With NWCOMPAT you can access old Novell directories, such as Novell Netware 3.x.

Server name

The server name follows the protocol in the binding path. The server name is optional if you are logged on to an Active Directory domain. Without a server name, serverless binding occurs; this means that Windows Server 2003 tries to get the "best" domain controller in the domain that's associated with the user doing the bind. If there's no server inside a site, the first domain controller that can be found will be used.

A serverless binding might look like this: LDAP://OU=Sales, DC=Thinktecture, DC=Local.

Port number

After the server name, you can specify the port number of the server process by using the syntax :xxx. The default port number for the LDAP server is port 389: LDAP://dc01.sentinel.net:389. The Exchange server uses the same port number as the LDAP server. If the Exchange server is installed on the same system — for example, as a domain controller of Active Directory — a different port can be configured.

Distinguished name

The fourth part that you can specify in the path is the distinguished name (DN). The distinguished name is a unique name that identifies the object you want to access. With Active Directory you can use LDAP syntax that is based on X.500 to specify the name of the object.

This is an example of a distinguished name:

 CN=Christian Nagel, OU=Consultants, DC=Thinktecture, DC=local 

This distinguished name specifies the common name (CN) of Christian Nagel in the organizational unit (OU) called Consultants in the domain component (DC) called Thinktecture of the domain Thinktecture.local. The part specified to the right is the root object of the domain. The name has to follow the hierarchy in the object tree.

You can find the LDAP specification for the string representation of distinguished names in RFC 2253 at www.ietf.org/rfc/rfc2253.txt.

Relative distinguished name

A relative distinguished name (RDN) is used to reference objects within a container object. With an RDN the specification of OU and DC is not needed, because a common name is enough. CN=Christian Nagel is the relative distinguished name inside the organizational unit. A relative distinguished name can be used if you already have a reference to a container object and if you want to access child objects.

Default naming context

If a distinguished name is not specified in the path, the binding process will be made to the default naming context. You can read the default naming context with the help of rootDSE. LDAP 3.0 defines rootDSE as the root of a directory tree on a directory server. For example:

 LDAP://rootDSE 

or

 LDAP://servername/rootDSE  

By enumerating all properties of the rootDSE, you can get the information about the defaultNaming Context that will be used when no name is specified. schemaNamingContext and configuration NamingContext specify the required names to be used to access the schema and the configuration in the Active Directory store.

The following code is used to get all properties of rootDSE:

 using (DirectoryEntry de = new DirectoryEntry()) { de.Path = "LDAP://treslunas/rootDSE"; de.Username = @"explorer\christian"; de.Password = "password"; PropertyCollection props = de.Properties; foreach (string prop in props.PropertyNames) { PropertyValueCollection values = props[prop]; foreach (string val in values) { Console.Write(prop + ": "); Console.WriteLine(val); } } } 

This program shows the default naming context (defaultNamingContext DC=explorer, DC=local), the context that can be used to access the schema (CN=Schema, CN=Configuration, DC=explorer, DC=local), and the naming context of the configuration (CN=Configuration, DC=explorer,DC=local), as shown in Figure 22-9.

image from book
Figure 22-9

Object identifier

Every object has a globally unique identifier (GUID). A GUID is a unique 128-bit number as you may already know from COM development. You can bind to an object using the GUID. This way you always get to the same object, regardless of whether the object was moved to a different container. The GUID is generated at object creation and always remains the same.

You can get to a GUID string representation with DirectoryEntry.NativeGuid. This string representation can then be used to bind to the object.

This example shows the path name for a serverless binding to bind to a specific object represented by a GUID:

 LDAP://<GUID=14abbd652aae1a47abc60782dcfc78ea> 

User name

If a different user from the one of the current process must be used for accessing the directory (maybe this user doesn't have the required permissions to access Active Directory), explicit user credentials must be specified for the binding process. Active Directory has multiple ways to specify the user name.

} 

Downlevel logon

With a downlevel logon the user name can be specified with the pre-Windows 2000 domain name:

 domain\username 

Distinguished name

The user can also be specified by a distinguished name of a user object, for example:

 CN=Administrator, CN=Users, DC=thinktecture, DC=local 

User principal name

The user principal name (UPN) of an object is defined with the userPrincipalName attribute. The system administrator specifies this with the logon information in the Account tab of the User properties with the Active Directory Users and Computers tool. Note that this is not the e-mail address of the user.

This information also uniquely identifies a user and can be used for a logon:

 Nagel@thinktecture.local 

Authentication

For secure encrypted authentication, the authentication type can also be specified. The authentication can be set with the AuthenticationType property of the DirectoryEntry class. The value that can be assigned is one of the AuthenticationTypes enumeration values. Because the enumeration is marked with the [Flags] attribute, multiple values can be specified. Some of the possible values are where the data sent is encrypted; ReadonlyServer, where you specify that you need only read access; and Secure for secure authentication.

Binding with the DirectoryEntry class

The System.DirectoryServices.DirectoryEntry class can be used to specify all the binding information. You can use the default constructor and define the binding information with the properties Path, Username, Password, and AuthenticationType, or pass all the information in the constructor:

 DirectoryEntry de = new DirectoryEntry(); de.Path = "LDAP://platinum/DC=thinktecture, DC=local"; de.Username = "nagel@thinktecture.local"; de.Password = "password"; // use the current user credentials DirectoryEntry de2 = new DirectoryEntry( "LDAP://DC=thinktecture, DC=local"); 

Even if constructing the DirectoryEntry object is successful, this doesn't mean that the binding was a success. Binding will happen the first time a property is read to avoid unnecessary network traffic. At the first access of the object, you can see if the object exists and if the specified user credentials are correct.

Getting Directory Entries

Now that you know how to specify the binding attributes to an object in Active Directory, you can move on to read the attributes of an object. In the following example, you read the properties of user objects.

The DirectoryEntry class has some properties to get information about the object: the Name, Guid, and SchemaClassName properties. The first time a property of the DirectoryEntry object is accessed, the binding occurs and the cache of the underlying ADSI object is filled. (This is discussed in more detail shortly.) Additional properties are read from the cache, and communication with the server isn't necessary for data from the same object.

In the following example, the user object with the common name Christian Nagel in the organizational unit Wrox Press is accessed:

 using (DirectoryEntry de = new DirectoryEntry()) { de.Path = "LDAP://treslunas/CN=Christian Nagel, " +  "OU=Thinktecture, DC=explorer, DC=local"; Console.WriteLine("Name: " + de.Name); Console.WriteLine("GUID: " + de.Guid); Console.WriteLine("Type: " + de.SchemaClassName); Console.WriteLine(); //... } 
Note

To have this code running on your machine, you must change the path to the object to access including the server name.

An Active Directory object holds much more information, with the information available depending on the type of the object; the Properties property returns a PropertyCollection. Each property is a collection itself, because a single property can have multiple values; for example, the user object can have multiple phone numbers. In this case, you go through the values with an inner foreach loop. The collection returned from properties[name] is an object array. The attribute values can be strings, numbers, or other types. Here, just the ToString() method is used to display the values.

 Console.WriteLine("Properties: "); PropertyCollection properties = de.Properties; foreach (string name in properties.PropertyNames) { foreach (object o in properties[name]) { Console.WriteLine(name + ": " + o.ToString()); } } 

In the resulting output, you can see all attributes of the user object Christian Nagel (see Figure 22-10). otherTelephone is a multivalue property that has many phone numbers. Some of the property values just display the type of the object, System.__ComObject; for example lastLogoff, lastLogon, and nTSecurityDescriptor. To get the values of these attributes, you have to use the ADSI COM interfaces directly from the classes in the System.DirectoryServices namespace.

image from book
Figure 22-10



Professional C# 2005
Pro Visual C++ 2005 for C# Developers
ISBN: 1590596080
EAN: 2147483647
Year: 2005
Pages: 351
Authors: Dean C. Wills

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net