Saturday, July 26, 2008 10:45 AM
bart
Using Active Directory Lightweight Directory Services (LDS) in Windows Server 2008
Introduction
It’s a while ago I’ve been posting here but as usual there are very good reasons (read: excuses) for it. It’s been incredibly busy finishing our work on the .NET Framework 3.5 SP1 release and lately I’ve been preparing for my TechEd South Africa talks for next week – I’m thrilled to present at this conference. One of my talks covers “LINQ to Anything” about writing custom LINQ providers and in this context I’m showing off LINQ to AD because of its relative simplicity compared to other more extensive LINQ providers.
However, there was a slight problem: I used to drag around laptop domain controllers for a while when doing the Microsoft SchoolServer project for Microsoft Belux a long while ago (at that time Windows Server 2003) but right now it’s a little impractical to do that because my demo machine needs to be joined to our corporate domain and obviously our IT department wouldn’t like (to say the very least) me to carry a full corporate domain controller to some random conference :-). Of course there’s virtualization technology to the rescue but the demo machine I’m using has not quite enough RAM and I’d love to run Hyper-V but the machine isn’t 64-bit capable. Oh well, time to upgrade I guess :-).
So the solution I came up with is to rely on Windows Server 2008’s Lightweight Directory Services (LDS) role, also formerly known as Active Directory Application Mode (ADAM) but now shipping as a built-in role in our server OS product (after being a separate download and a Windows Server 2003 R2 “Disc 2” component). In this post I’ll outline how to set up LDS and how to use it.
Preparing the installation
First of all, this post assumes you have a Windows Server 2008 installation up and running already. On to the real matters now. It’s a common phenomenon to try something new at the office and have it working but find it not working on some random flight when preparing for the talk. Here’s a headache-medication saver: loopback adapters. More than once I’ve found network-driven applications now working correctly in a fully disconnected situation for various network stack related reasons, so I realized pretty quickly I didn’t have a loopback adapter installed. Installing one is easy: in Computer Management (now known as Server Manager), go to the Device Manager and add a piece of legacy hardware:

Follow the instructions to select the network adapter from the list:
and let the thing install. Ultimately you’ll have an always (though fake) connected computer, ideal to save presentation missions where networks are always influenced by Murphy’s law :-).
Installing LDS
To install LDS, select Active Directory Lightweight Directory Services Setup Wizard from Administrative Tools:
This will bring up the wizard that guides you through the installation and configuration of a new LDS instance. The concept of an instance is important to understand – you can regard an instance as a stand-alone (meaning not necessarily related to any domains) Active Directory database that can be reached by clients for typical directory operations over well-known protocols like LDAP. That’s precisely what I need: a light-weight (hence the name) instance of AD that isn’t linked to any AD domain whatsoever and reachable through LDAP (LINQ to AD used to be known as LINQ to LDAP).
Click through the first steps of the wizard to create a new instance – we won’t go into advanced topics such as replication:
Next we’ll give our instance a name, e.g. Demo. This information will ultimately be used to create a Windows service (whose name is prefixed with ADAM_) as well as the database under %ProgramFiles%\Microsoft ADAM\<instance name>\data.
Next, we’ll select the port number to listen on. If you’re not running any other directory service yet, the wizard will propose to use ports 389 (LDAP) and 636 (SSL) which are both the typical ports for the respective protocols. Indeed, it will just make your computer look like a typical directory service to client computers. However, if you already have a directory service (be it AD or AD LDS) running or plan to do so, alternative ports in the 50000 range will be proposed. We’ll stick with default 389 but make sure to remember the port number as you’ll need it when writing client apps:
Next, the wizard asks to create an Application Directory Partition. Expensive word, simple concept. Essentially an application partition is a part of the hierarchical directory services database that will contain your application’s data, and as every node in such a directory hierarchy it needs to have a distinguished name, e.g. CN=Demo,DC=bartdesmet,DC=local. We’ll create such a partition during the LDS instance creation but you can also choose to do it later (although that will complicate matters and require more code).
In the few steps following, the wizard will ask where to store the database – it’s okay to stick with the defaults – and what account to run the service under (Network Service is recommended for a more secure configuration):
Obviously services need some administrator that will be allowed to reconfigure the service (using the ADSI Editor for example, see further), so we’ll have to select an account that will be granted those permissions. You can use local accounts but also accounts from the domain the computer is joined to (as I’m doing below):
Last but not least, we’re presented a list of LDF files that can be imported in the instance. These get installed under the Schema partition of the instance and carry the schema data for various classes available in the instance to store data with:
I’m just selecting MS-User.LDF for now. It’s interesting to know where the wizard gets these files from: %systemroot%\ADAM\*.LDF. In fact, LDF files are just text files that look like this (for a full LDF file, see your installation):
#==================================================================
# @@UI-Description: AD LDS user class and related classes.
#
# This file contains user extensions for default ADAM schema.
# It should be imported with the following command:
# ldifde -i -f MS-User.ldf -s server:port -b username domain password -k -j . -c "CN=Schema,CN=Configuration,DC=X" #schemaNamingContext
#
#==================================================================
# Attributes
dn: CN=Serial-Number,CN=Schema,CN=Configuration,DC=X
changetype: ntdsschemaadd
objectClass: top
objectClass: attributeSchema
cn: Serial-Number
attributeID: 2.5.4.5
attributeSyntax: 2.5.5.5
isSingleValued: FALSE
rangeLower: 1
rangeUpper: 64
showInAdvancedViewOnly: TRUE
adminDisplayName: Serial-Number
adminDescription: Serial-Number
oMSyntax: 19
searchFlags: 0
lDAPDisplayName: serialNumber
schemaIDGUID:: MnqWv+YN0BGihQCqADBJ4g==
systemOnly: FALSE
The idea is simple: for each of the class attributes you’ll find a definition. Notice the file also has a comment for the ldifde (a command-line tool) invocation if you want to import LDF files after running the wizard.
Finally, the wizard is ready to do the installation:
Verifying the installation
Time to check what the wizard has installed. First, you’ll find a file containing the EDB instance database:

and in the Service Control Manager a new service will have been registered with the name ADAM_Demo which should have been started by the wizard already:
Using the LDP tool (Start, Run, ldp.exe) we can connect to the instance. Use Connection, Connect and specify the name of the machine (localhost):
Next, do a bind using the current credentials:
and go to View, Tree to display the contents of the database, for example connecting to our application partition:
The instance will obviously be pretty empty (still):
In addition you can use ADSI Edit from the Administrative Tools to connect to the instance to see the imported schema data:
Right-click the root node and choose Connect To. The connection settings should look like this:
In the Schema list you’ll find CN=User which we imported (amongst others) earlier during the execution of the wizard. Search for “dn: CN=User,CN=Schema,CN=Configuration,DC=X” in the LDF file to find the import:
Using it
Finally we’ll write a tiny little bit of System.DirectoryServices code in C# to use the instance. Make sure to import the System.DirectoryServices assembly in Visual Studio:
and write the following piece of code:
using System;
using System.DirectoryServices;
namespace PopulateLdap
{
class Program
{
static void Main()
{
DirectoryEntry entry = new DirectoryEntry("LDAP://localhost/CN=Demo,DC=bartdesmet,DC=local");
foreach (DirectoryEntry e in entry.Children)
Console.WriteLine(e.Name);
DirectoryEntry user1 = entry.Children.Add("CN=bartde", "user");
user1.Properties["givenName"].Value = "Bart";
user1.Properties["sn"].Value = "De Smet";
user1.CommitChanges();
entry.CommitChanges();
foreach (DirectoryEntry e in entry.Children)
Console.WriteLine(e.Name);
}
}
}
where the LDAP path specified should obviously point at the application partition created above. Execution looks like:
and LDP will show the new directory entry:
Ready to rock!
Del.icio.us |
Digg It |
Technorati |
Blinklist |
Furl |
reddit |
DotNetKicks