Introduction
There are many code snippets out there for DirectoryServices but trying to find one that actually connects to and works with Sun One LDAP or any other platform other than AD is not so easy! This will help users work with alternative LDAP solutions.
Background
The concept of LDAP and having web pages talk to it or even other client tools is fairly straight forward. Unfortunately trying to figure out what it takes to actually get results from anything but Active Directory (AD) is not the easiest thing to do. Hopefully you will find this information useful.
** Note all code is based on a standard install of Sun One with no added OUs or anything specific.
Using the Code
This article is mostly code snippets. I will demonstrate how to connect, add, update, delete and find LDAP entries. This is based on Sun One, but will most likely be useful for anyone that has LDAP that is not AD.
First there are 2 separate methods for working with LDAP. There is the System.DirectoryServices
method for dealing with DirectoryEntry
and DirectorySearcher
. and then there is the System.DirectoryServices.Protocols
for a more down and dirty approach of sending specific requests.
* You will probably want to wrap these statements in try catch
blocks in case errors happen for proper handling.
Let's explore them both!
First things. In your project, add a reference to System.DirectoryServices
and / or using System.DirectoryServices.Protocols
.
Add one or both of the following to the using
clauses to make life easier:
using System.DirectoryServices;
using System.DirectoryServices.Protocols;
To connect directly, there are a few things to note. There are Authentication Types. These may need to be changed based on your connectivity, but if they are not configured correctly you can get strange errors. Also the user / password is different from AD. You will have to explicitly use a fully qualified username for most 3rd party LDAP servers.
To simply connect with Protocols, you can use the following code as an example:
LdapDirectoryIdentifier ldapDir = new LdapDirectoryIdentifier("servername", 9605);
LdapConnection ldapConn = new LdapConnection(ldapDir);
ldapConn.AuthType = AuthType.Basic;
System.Net.NetworkCredential myCredentials =
new System.Net.NetworkCredential("uid=admin,ou=Administrators,
ou=TopologyManagement,o=netscapeRoot", "password");
ldapConn.Bind(myCredentials);
Now, without using the Protocols, you have to connect and perform an action all at the same time, therefore you don't have control of leaving the connection established like you do with Protocols. For this example, we will connect and start with a DirectoryEntry
. In this example, the entry is the root.
DirectoryEntry dirEntry = new DirectoryEntry();
dirEntry.Path = @"LDAP://servername:9605/dc=example,dc=com";
dirEntry.Username = "uid=admin,ou=Administrators,
ou=TopologyManagement,o=netscapeRoot";
dirEntry.Password = "password";
dirEntry.AuthenticationType = AuthenticationTypes.ServerBind;
dirEntry.RefreshCache();
The RefreshCache
method (last line of code above) is the actual establishment of the connection. It connects and loads all of the properties and attributes of the DirectoryEntry
.
Now let's add a new user! With the protocols method, this looks like this. Now it's important to note that LDAP servers will have requirements for adding a user, i.e. must have the correct objectclasses, and must have certain attributes. Below are the typical attributes for Sun One. Please check your LDAP server for Attribute requirements for entries.
AddRequest addme = new AddRequest(@"uid=nuser,ou=People,dc=example,dc=com");
addme.Attributes.Add(new DirectoryAttribute("objectclass", new object[]
{ "top", "person", "organizationalPerson", "inetorgPerson" }));
addme.Attributes.Add(new DirectoryAttribute("uid", "nuser"));
addme.Attributes.Add(new DirectoryAttribute("givenName", "new"));
addme.Attributes.Add(new DirectoryAttribute("sn", "user"));
addme.Attributes.Add(new DirectoryAttribute("cn", "new user"));
addme.Attributes.Add(new DirectoryAttribute("userPassword", "nuser"));
ldapConn.SendRequest(addme);
Ok so how do I add something without the Protocols method? Fear not, it can be done!
DirectoryEntry newUser = dirEntry.Children.Add
("uid=nuser,ou=People,dc=example,dc=com", "person");
newUser.Properties["objectClass"].Value = new object[]
{ "top", "person", "organizationalPerson", "inetorgPerson" };
newUser.Properties["uid"].Value = "nuser";
newUser.Properties["givenName"].Value = "new";
newUser.Properties["sn"].Value = "user";
newUser.Properties["cn"].Value = "new user";
newUser.Properties["userPassword"].Value = "nuser";
newUser.CommitChanges();
** Note the dirEntry
is the same as above, which is the root of the server. This will add a user to the root of the LDAP server directory. The CommitChanges
method does the work for us.
Ok now let's find the new user! (This is useful for updating the user properties or just checking if they exist!)
SearchRequest findme = new SearchRequest();
findme.DistinguishedName = "ou=People,dc=example,dc=com";
findme.Filter = "(objectClass=person)";
findme.Scope = System.DirectoryServices.Protocols.SearchScope.Subtree;
SearchResponse results = (SearchResponse)ldapConn.SendRequest(findme);
SearchResultEntryCollection entries = results.Entries;
for (int i = 0; i < entries.Count; i++)
{
SearchResultEntry entry = entries[i];
IDictionaryEnumerator attribEnum = entry.Attributes.GetEnumerator();
while (attribEnum.MoveNext())
{
DirectoryAttribute subAttrib = (DirectoryAttribute)attribEnum.Value;
for (int ic = 0; ic < subAttrib.Count; ic++)
{
attribEnum.Key.ToString();
subAttrib[ic].ToString();
}
}
}
The same thing without the Protocols:
DirectorySearcher search = new DirectorySearcher(dirEntry);
search.Filter = "(objectClass=person)";
search.SearchScope = System.DirectoryServices.SearchScope.Subtree;
SearchResultCollection searchResults = search.FindAll();
for (int i = 0; i < searchResults.Count; i++)
{
System.Collections.IDictionaryEnumerator subColl =
searchResults[i].Properties.GetEnumerator();
while (subColl.MoveNext())
{
ResultPropertyValueCollection pc = (ResultPropertyValueCollection)subColl.Value;
System.Collections.IEnumerator subPcol = pc.GetEnumerator();
while (subPcol.MoveNext())
{
subColl.Key.ToString();
subPcol.Current.ToString();
}
}
}
Ok now to modify something! The below will add a user to a group.
ModifyRequest request = new ModifyRequest();
request.DistinguishedName = distinguishedgroupname;
DirectoryAttributeModification dirmod = new DirectoryAttributeModification();
dirmod.Operation = DirectoryAttributeOperation.Add;
dirmod.Name = "uniquemember";
dirmod.Add(distinguishedusername);
request.Modifications.Add(dirmod);
ModifyResponse response = (ModifyResponse)ldapConnection.SendRequest(request);
The below will remove a user from a group. Notice the dirmod.Operation
which specifies the type of modification request.
ModifyRequest request = new ModifyRequest();
request.DistinguishedName = distinguishedgroupname;
DirectoryAttributeModification dirmod = new DirectoryAttributeModification();
dirmod.Operation = DirectoryAttributeOperation.Delete;
dirmod.Name = "uniquemember";
dirmod.Add(distinguishedusername);
request.Modifications.Add(dirmod);
ModifyResponse response = (ModifyResponse)ldapConnection.SendRequest(request);
And lastly code on how to delete an object!
DeleteRequest request = new DeleteRequest(distinguishedname);
DeleteResponse response = (DeleteResponse)ldapConnection.SendRequest(request);
With this, you should be able to work with LDAP solutions to create your own user management solutions. I created a web site to add / delete users and modify groups for users with this code. You can also build a first time synch to load all the current user permissions that were stored in a database into LDAP. Some 8000 users loaded in about 10 minutes during cutover.
Have fun, happy coding!
History
- 24th June, 2009: Initial post