.NET Client Classes for openldap/winldap






4.88/5 (15 votes)
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:
- LDAP Implementation Cookbook (IBM Red Book) (ibm.com)
- A Recipe for Configuring and Operating LDAP Directories (georgetown.edu)
- Lightweight Directory Access Protocol (v3) - rfc2251(faqs.org)
- LDAP (v3) - Attribute Syntax Definitions - rfc2252 (faqs.org)
- String Representation of LDAP Search Filters - rfc2254 (faqs.org)
- LDAP (v3): UTF-8 String Representation of Distinguished Names - rfc2253 (faqs.org)
- Technical Overview of Directory Services Using the X.500 Protocol - rfc1309 (faqs.org)
- COSINE and Internet X.500 Schema - rfc1274 (faqs.org)
- The LDAP URL Format - rfc2255 (faqs.org)
- The LDAP Data Interchange Format (LDIF) - Technical Specification (faqs.org)
- OpenLDAP 2.1 Administrator's Guide (openldap.org)
- OpenLDAP 2.0 Schema Extension to support MS/Outlook, Netscape 4.5+ (yolinux.com)
- Common LDAP RFCs (mskb)
- Introduction to Lightweight Directory Access Protocol (LDAP) (mskb)
- OutLook2000: (CW) How to Install and Use the LDAP Service (mskb)
- HOWTO: Use ADO to Access Objects Through an ADSI LDAP Provider (mskb)
- Obtaining an Object Identifier - OID (msdn)
Winldap related:
- Lightweight Directory Access Protocol (msdn)
- Understanding LDAP (microsoft.com)
- Error Message: 0x80090322 When Binding with SSL to Site Server LDAP (mskb)
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"
- HOW TO: Enable Schannel Logging (mskb)
- Microsoft LDAP Error Codes (mskb)
Active Directory related:
- Microsoft Visual Studio.NET Server Explorer Extensions for Active Directory (msdn)
- Using LDIFDE to Import and Export Directory Objects to Active Directory (mskb)
- How to Modify Schema Information Using the Ldifde Utility(mskb)
- Toolbox for LDAP Directory Developers (mskb .doc)
- Active Directory Architecture (msdn)
- Active Directory Schema (msdn)
- Syntaxes for Active Directory Attributes (msdn)
- Characteristics of Object Classes (msdn)
- LDIF Scripts (msdn)
- Extending the AD Schema (msdn)
- An ADSI Primer (winscriptingsolutions.com)
- Active Directory Glossary (microsoft.com)
- Using Good Programming Practices with LDAP (msdn)
- How to Use Csvde.exe to Import Contacts into Active Directory (mskb)
- HOW TO: Use Csvde to Import Contacts and User Objects into Active Directory (mskb)