Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

.NET Client Classes for openldap/winldap

0.00/5 (No votes)
11 Mar 2003 1  
An example of using LDAP/OpenLDAP with .Net

LDAP - Lightweight Directory Access Protocol

Environments:

Client: Server:
openldap (plain|tls) openldap
winldap (plain|tls) openldap
openldap (plain|tls) Active Directory
winldap (plain|tls) Active Directory

NOTE: Before using the library you have to go through the code and review it.

Building openldap client lib:

Here are the steps to build openldap on windows. To build the client library there is not much tweaking to be done. I used openldap-2.1.12. The .dsp and .dsw files are under ..\build\ directory. If you open main.dsw, it contains openldap server as well as ldap client library. For the client you need to build libldap_r and liblber projects. I didn't use SASL authentication mechanisms so i removed SASL and Regex dependency also from the ldap library (although, it's not hard to build with sasl/regex support). To remove SASL/Regex dependency expand setup project. Open portable.nt file and comment out

//#define HAVE_REGEX_H 1

//#define HAVE_CYRUS_SASL 1

(Or otherwise follow instructions from here .)

Right click on libldap_r (thread safe version) and liblber projects and Rebuild. This should build without any problems. Now you have to set the VS.NET search directory for libraries to where the outputed oldap_r.lib and olber32.lib are. And the same for include files:

..\openldap-2.1.12\Debug or ..\openldap-2.1.12\Release or some common directory or renamed debug and release files.
..\openldap-2.1.12\include

Building openldap server on Windows for testing purposes:

Check the build instructions here, this is for openldap-2.0.xx versions.

You can also successfully build openldap-2.1.xx and I used Sleepycat Berkley's db-4.1.xx, and cyrus-sasl-1.5.xx with it. When everything is built you have to copy *.exe and *.dll files to some directory that will be the base directory for openldap server.

You will need to copy the schema directory from ..\openldap\openldap-2.1.12\servers\slapd\schema to your base openldap dir and the sample slapd.conf file from ..\openldap\openldap-2.1.12\servers\slapd\slapd.conf.

In slapd.conf add ucdata-path before any include statements. Like this:

ucdata-path "X:/openldap-2.1.12/ucgendat". 

Then open command prompt and run

ucgendat.exe -o X:/openldap-2.1.12/ucgendat

If you get this error: error loading ucdata (error -127), you'll know that ucgendata wasn't setup. In 2.0.xx versions it wasn't needed.

Fill/Change the rest of slapd.conf to your needs. Check various resources, specifically slapd.conf man page at http://www.openldap.org/software/man.cgi and type slapd.conf also check Quick-Start Guide and Administrator's Guide.

To debug possible errors you can start slapd -d 255 to do this you need to compile with LDAP_DEBUG. This can be added in portable.nt file, it's under setup project; somewhere at the top add:

#define LDAP_DEBUG 1

If you want to add ssl/tls support, you can do that through openssl. You have to get the latest openssl version (for example openssl-0.9.7a) and follow the instructions in INSTALL.W32 file that comes with the package. After you've built openssl into dll or static libraries you have to add it's .lib/.h directories to VS.NET's search directory for libraries/include files. Now you have to open portable.nt from setup project of openldap solution. somewhere at the top add this:

#define HAVE_TLS 1 
#define HAVE_OPENSSL_SSL_H 1 
#pragma comment(lib, "ssleay32r.lib") 
#pragma comment(lib, "libeay32r.lib")

And build openldap. Now you have to edit the slapd.conf file. Related options are: TLSVerifyClient, TLSCertificateFile, TLSCertificateKeyFile, TLSCACertificateFile, TLSCipherSuite, etc.

Now you can start ldap to listen for ssl/tls connections:

slapd -h "ldaps://somehost ldap://somehost

Although ldaps:// is not needed when using ldap_start_tls_s because it talks on normal ldap port (389) and not on 636 for ssl. When connecting with winldap client the CA of server's certificate has to be trusted by the client PC, which means it has to be installed under trusted CA's. You can check if there are any problems with server certificate by connecting to the server with Internet Explorer. More trouble shooting info related to winldap is available by searching groups.google.com for: ldap_sslinit troubleshoot group:microsoft.public.platformsdk.active.directory there you will find mskb article.

Ldap .NET Class Usage

Connection:

LdapClient c = new  LdapClient("127.0.0.1", 
               LdapClient.DefaultPort,true /*version 3?*/, true /*use tls?*/);
c.ldap_simple_bind_s("bind_dn", "your_pass");

Searching:

LdapResult res;
int count = c.ldap_search_ext_s("dn_to_start_the_search_at", 
              LDAPSearchScope.LDAPSCOPE_SUBTREE,
              "sn=*",         /* search filter */
              new string[0],  /* attribs to return, empty for all */
              false,          /* return attrsonly? */
              60,             /* allow 60 secs for the search */
              0,              /* 0 == no size limit on returned entries */
              out res);

Console.WriteLine("Search Returned: {0}", count);

foreach(Oldap.LdapEntry entry in res)
{
    Console.WriteLine("dn:{0}", entry.DN);
    foreach(Oldap.LdapAttribute attr in entry)
    {
        if(attr.Name == "string_type?")
            foreach(string val in attr.StringValues)
                Console.WriteLine("{0}: {1}", attr.Name, val);
        else if(attr.Name == "binary_type?")
            foreach(Byte[] val in attr.BinaryValues)
            {
                mem = new MemoryStream();
                mem.Write(val, 0, val.Length);
                //do something with it

            }
    }
    Console.WriteLine();
}

Adding new Entry

(supported types: String or String[], Byte[] or array of Byte[]):

string entryDN = "dn_of_new_entry";
ListDictionary attrval = new ListDictionary();
attrval["objectClass"]=new string[]{"top", "person"}; 
//person class is abstract in AD

attrval["cn"]=new string[]{"test"};
attrval["sn"]="test";

//Byte[] example. To add multiple binary values you have 

//to pass array of byte[], so something like

//ArrayList that has Added byte[]s and then gives the array 

//with ToArray method should work

//Bitmap bmp = new Bitmap("..\\..\\some.bmp"); 

//mem = new MemoryStream();  

//bmp.Save(mem, ImageFormat.Bmp);

//attrval["personPhoto"]= new object[]{mem.ToArray()}; //aray of byte[]     

//or

//attrval["personPhoto"]= mem.ToArray(); //byte[] 

//personPhoto is custom attribute with 

//SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 

//in AD it's 2.5.5.10 

//To support it i defined a new objectClass 

//that includes it, and "person" objectClass

//used in above example doesn't know about it.


c.ldap_add_s(entryDN, attrval);

if(c.ldap_compare_s(entryDN, "cn", "test") == true) 
//check if value exists for attrib under specific entry

Replacing attribute in existing entry:

attrval["sn"]="test_modified";
c.ldap_mod_replace(entryDN, attrval);

Adding attribute to existing entry:

attrval["telephoneNumber"]=new string[]{"phone1","phone2"};
c.ldap_mod_add(entryDN, attrval);

Removing attribute from existing entry:

attrval["telephoneNumber"]=new string[0];          
//remove attribute completely

attrval["telephoneNumber"]=new string[]{"phone2"}; 
//remove specific value from attribute                                                

//or whole attribute if it's the only value


c.ldap_mod_delete(entryDN, attrval);

Deleting whole entry:

c.ldap_delete_s(entryDN);

Exception thrown:

LDAPException
LDAPExceptionPartialResult - thrown when searching and specifying size limit. 
partial_count data member has the returned count.
InvalidCastException

The rest of ldap functions including async methods, referrals (LDAP_OPT_REFERRALS), etc... are to be added on as needed basis.

Reference:

Winldap related:

Common SSL errors with winldap:
0x80090322 - "The target principal name is incorrect"
0x80090325 - "The certificate chain was issued by an authority that is not trusted"

Active Directory related:

Disclaimer: THIS CODE AND INFORMATION IS PROVIDED 'AS IS' WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.

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