Last post May 29, 2007 11:27 AM by amarsas
Dec 28, 2005 11:40 AM|amarsas|LINK
I am a newbie with enterprise directories. I am trying to write an ASP.NET application to fetch some data from my university LDAP enterprise directory. There are 2 types of access allowed to the LDAP server. One is a anonymous access and another is the access
that exists mainly to give privileged accounts access to person information that can otherwise not be publicly viewed. These privileged accounts, called Y Services, are primarily used to look up person data and authorize people on this data.
Now, i was able to use the anonymous access priviliges and view the data from LDAP server. What i want to do is to use the
Y services and view the person information that cannot be accessed via the anonymous access. For example i want to view the
date of birth for the person which is available in the Y Services access.
The university instructions say the following:
What you see in Y Services is dependent on how you bind (anonymous, simple, SASL EXTERNAL) and the amount of privileges the bound user has. Connecting to
Y Services requires the use of
TLS client certificate authentication, meaning you must have a signed certificate from the uiniversity in order to connect. Users bound anonymously can only search on ID and can only see the DN (distinguished name) of any user. Users that have performed
a SASL EXTERNAL bind can only see those attributes they have been approved to see (for all users), and only if the corresponding service is ACTIVE.
Now, i know that the TLS client certificate has been installed on my server by my Sys admin.
Please tell me the steps to do the bind and fetch the date of birth for all people in department X.
Here is the anonymous bind code.
iNumProperties = 0
Results = searcherLdap.FindAll
iNumProperties = Results.Count()
iNumProperties = 0
propcoll = Result.Properties
iOnce = 0
arrFName(iNumProperties) = obProp
arrLName(iNumProperties) = obProp
arrEmail(iNumProperties) = obProp
iNumProperties = iNumProperties + 1
Please help me!! THANKS IN ADVANCE!!
Jan 05, 2006 12:39 PM|dunnry|LINK
Jan 05, 2006 03:26 PM|amarsas|LINK
Thanks Ryan. Appreciate your help. Could you please also find out if ASP.NET supports SASL External Binds? But please do post whatever your pal has to say.
Jan 06, 2006 02:33 PM|dunnry|LINK
Jan 10, 2006 09:41 AM|amarsas|LINK
Yes i have tried using the securesockets layer option. But can you please show me an example code snippet in VB.NET that binds a particular client certificate (or tells the application to use a particular client certificate) while connecting to the campus
Jan 11, 2006 09:28 AM|dunnry|LINK
Jan 11, 2006 03:10 PM|amarsas|LINK
Are you using a single certificate for the university server for each account? Or do you have a unique certificate per user?
- THE UNIVERSITY MIDDLEWARE GROUP PROVIDED US WITH A CLIENT CERTIFICATE TO USE ON OUR WEBSERVER WHILE CONNECTING TO THE LDAP. THEY SAID THAT THIS CERTIFICATE IS FOR THE SERVICE ASSIGNED TO MY DEPARTMENT ON LDAP SERVER. SO I BELIEVE IT IS NOT ACCOUNT SPECIFIC
RATHER MACHINE SPECIFIC CERTIFICATE THAT IDENTIFIES THAT THE AUTHORIZED CLIENT (IN THIS CASE REQUEST SENT OUT BY WEBSERVER) IS TRYING TO ACCESS THE SERVICE ON LDAP.
Are you using this in an ASP.NET app (I have to ask) or a desktop app?
- I AM USING ASP.NET APPLICATION.
If you have the certificate (public key side) of a single university certficate, then you need to use the Certificate Wizard in the Cert MMC to install it in the machine cert store for it to be used in ASP.NET. Otherwise the certificate will not be found
when using ASP.NET. This certificate should also be set to be trusted if it does not come from Verisign or other CA.
- THE CERTIFICATE IS IN THE MACHINE STORE ALONG WITH THE PRIVATE KEY.AND I AM PRETTY SURE IT IS TRUSTED SINCE WE HAVE A UNIVERSITY CERTIFICATE CHAIN IN THE TRUSTED LIST.
If you turn on SChannel logging you might get more information why your secure SSL bind is failing.
-I WILL TRY THIS
What error are you getting now?
-THE FOLLOWING IS THE ERROR THAT I AM GETTING.
System.Runtime.InteropServices.COMException (0x8007203A): The server is not operational at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail) at System.DirectoryServices.DirectoryEntry.Bind() at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne) at System.DirectoryServices.DirectorySearcher.FindAll() at rabiespersonnel.WebForm1.btnReset_Click(Object sender, EventArgs e) in
THE CODE FAILS AT THE FINDALL() METHOD.
What VB.NET code snippet are you attempting to use now with SSL?
- THE FOLLOWING IS MY VB.NET CODE
deLdapConn.AuthenticationType = AuthenticationTypes.SecureSocketsLayer
searcherLdap.Filter = "(department=Personnel)"
For Each obProp
If strKey = "givenName"
Then ' If the fieldname is firstname then
Thanks again Dunnry. I really appreciate your help.
Jan 13, 2006 11:41 AM|amarsas|LINK
I turned on the SChannel logging. Looks like when i try to access the aspx website in my browser the server certificate prompt asks me whether i trust the certificate, i say yes then it shows me the webpage. At the end of this process i see 2 events logged
in by SChannel. One is the server handshake and one is the client handshake.
Now, when i click a button on the webpage to connect to the LDAP server, it just returns an error on the webpage saying "The server is not operational"
I do not see any event logging by SChannel in the event viewer. I strongly suspect that when my application tries to connect to the LDAP server the Ldap server somehow does not look for the client certificate installed on my webserver for the handshake.
I checked and saw that the client certificate was installed in the Machine store along with the private key. I also made sure that the application pool that ASPNET uses has access to this client certificate.
Is there some way that you can specify in the code to use a particular client certificate while connecting to the LDAP server?
Thanks in advance.
Jan 16, 2006 03:54 PM|dunnry|LINK
I don't know of any way to specify a particular cert for use with LDAP. Since the certificate is on the server and you are only trusting it, it really does not make sense to select one either. Either you have a trusted certificate installed on your side
in negotiation with the server, or you do not.
I have to admit that I have not ever tried doing this with a 3rd party LDAP store. You might have more success with System.DirectoryServices.Protocols here since it will give you more control over the process.
There are a few things you can try to eliminate the issues. First, create a console app to get ASP.NET out of the picture. Next, make sure you have the Schannel logging in debug mode. It sounds like you have some configuration problems on the client with
the certificate if it is prompting you to trust it. The schannel logging is going to be the most important thing. Try posting the log file here when you get it into debug mode.
Finally, after you create the console app, just bind directly to an object and do not perform a search with the DirectorySearcher. The searcher can complicate things and we just want to see if you can even get a good bind. Simply bind directly to the object
you want and try to read an attribute.
See where this leads you for now.
Jan 18, 2006 02:22 PM|amarsas|LINK
Thank you again Dunnry.
My certificate is in the Local Machine Store of the webserver along with the private key. Plus the account under which asp.net runs has access to this certificate.
I am still getting the following error "The server is not operational"
I also tried another thing. I used the ldp.exe application which comes along with the windows support tools and tried to connect to the ldap server. But it fails saying that the server is down.
My university has a OpenLDAP instance running on a Debian Linux (if this helps in anyway) and i am trying to connect to it using my windows 2003 server (through asp.net appl).
You commented - "You might have more success with System.DirectoryServices.Protocols"
I believe this is a part of the .NET 2.0 Framework and i cannot use it because i use visual studio.net 2003 which supports framework v 1.1
About the console application, i am working on it but since it is my first time, i would appreciate if you could please post some sample code snippet that binds directly to an object and does not perform a search with the DirectorySearcher as you wanted.
I really appreciate all the help.
Jan 23, 2006 09:10 AM|amarsas|LINK
Finally got the client certificate on my webserver working. Turns out my sys admin had blocked off access by the LDAP server in the firewall.
Anyways, now Schannel gives me a message saying that the client authentication was successfull and digital certificate was supplied and provides a bunch of details about the certificate. The central LDAP server admin also said that he can see that my webserver
had been connecting to the LDAP server successfully using the client certificate.
Now the problem is about the SASL EXTERNAL bind. The LDAP server admin says that now since i have opened up a secure channel, i will have to bind using this type of bind to fetch data from the LDAP server. He says that this type of bind is required by the
LDAP server before i can proceed to query. Please tell me a way to do this type of bind.
The following are his instructions:
1. initialize the connection and set LDAPv3
2. startTLS on the connection
3. perform a SASL EXTERNAL bind
4. search on the filter
5. get the results from the search
6. get the DN
7. print out the entire entry
I was able to achieve steps 1 and 2. But i am stuck up on step 3. I do not know how to perform this bind using ASP/VB.NET
Jan 25, 2006 10:38 AM|dunnry|LINK
Jan 30, 2006 03:44 PM|amarsas|LINK
Thanks again Dunnry.
Tried the steps that you suggested, but seems that is is failing at the FindAll() method. The LDAP server admin says that SDS probably does not have a SASL EXTERNAL bind method. This is absolutely REQUIRED before i can query for the DN.
Another option that he suggested was :-
"We've received several questions from people with ED-ID services whose libraries do not support SASL External.In response to this we are considering a service to act as a proxy to ED-ID.Instead of requiring LDAPv3 + SASL EXTERNAL + CLIENT AUTH, the proxy
will require HTTPS + CLIENT AUTH.The proxy would not support all LDAPv3 commands, only searches.If anyone is interested in such a service please drop me a note. "
What do you think? Do you think we should go for this option. Or is it worthwhile to use .Net framework 2.0 with VS-2005 and try out the SASL binding?
Feb 02, 2006 01:08 PM|dunnry|LINK
Feb 02, 2006 02:04 PM|amarsas|LINK
Thanks a ton for keeping up with my post.
I am getting VS.NET 2005 today or tomorrow and will then use SDS.Protocols to test the things.
Let me post a code snippet in some other language that is available from the middleware group. See if you can figure out a code snippet to achieve the same using .NET 1.1. If you think its too much of a hasssle then lets wait and see how .NET 2.0 handles
the same. I will keep you posted.
This example uses the native Windows
LDAP API (WinLDAP) to connect to ED-ID. Similar code could probably be compiled as a COM object or DLL for use with .Net or
VB. Pay special attention to the notes section at the beginning of the example.
Download WinLDAP Example
Lines 24-28 include necessary headers
Lines 37-49 declare variables necessary for example
Lines 56-62 initialize the
Lines 64-70 set LDAPv3 and ensure
SSL in on
Lines 73-81 connect to ED-ID
Lines 85-90 perform a SASL EXTERNAL bind
Lines 93-100 search on the filter, get the first entry, and grab its DN
Lines 103-128 print out all viewable attributes and their values for the person
Lines 132-138 determine if the person has the specified affiliation
Lines 140-141 clean up
2 * winldap-edid.c
3 * This code is an example of how to connect to ED-ID, do a
4 * SASL EXTERNAL bind with a client certificate, search for a user,
5 * print out the user's attributes, and then determine if the user
6 * has the proper affiliation specified. This is but the tip of the
7 * iceberg for authorization that can be done with ED-ID.
9 * Notes: * You must have a client certificate that has been issued
10 * by the VT Middleware CA to connect to ED-ID.
11 * * You must have a service entry that corresponds to your
12 * client certificate to be able to view entries
13 * * You must have imported the VTCA chain into the
14 * Windows keystore before this code will work properly.
15 * This is available at https://vtmwra.eprov.iad.vt.edu/cacert,
16 * or click on "immediate installation" and run the .exe at
17 * http://www.pki.vt.edu/download/ie6.html. This will
18 * automatically install the CA for you.
19 * * Your client certificate must also be in the Windows
20 * keystore (see Appendix for instructions)
21 * * You must link this against wldap32.lib
24 #include <windows.h>
25 #include <ntldap.h>
26 #include <winldap.h>
27 #include <stdio.h>
28 #include <winber.h>
31 * Do a SASL EXTERNAL bind, search for the user with the supplied UUPID,
32 * print all attributes for the person, determine if the person has the
33 * specified affiliation.
35 int main(int argc, char* argv)
37 LDAP* ld = NULL;
38 INT retVal = 0;
39 PCHAR pHost = "id.directory.vt.edu";
40 int port = 636;
41 char* base = "ou=people,dc=vt,dc=edu";
42 char* filter = "(uupid=UUPID)";
43 LDAPMessage *result, *entry;
44 char *dn;
45 char *cmpAttr = "eduPersonAffiliation";
46 char *cmpVal = "VT-ACTIVE-MEMBER";
47 struct berval cred;
48 struct berval *servercredp;
49 ULONG version = LDAP_VERSION3;
51 cred.bv_val = "";
52 cred.bv_len = strlen(cred.bv_val)*sizeof(char);
54 printf("\nConnecting to host \"%s\" ...\n",pHost);
56 // Create an LDAP session.
57 ld = ldap_sslinit(pHost, port, 1);
58 if (ld == NULL)
60 printf( "ldap_sslinit failed with 0x%x.\n",GetLastError());
61 return -1;
64 // Specify version 3; the default is version 2.
65 printf("Setting Protocol version to 3.\n");
66 retVal = ldap_set_option(ld,
70 retVal = ldap_set_option(ld,LDAP_OPT_SSL,LDAP_OPT_ON);
72 // Connect to the server.
73 retVal = ldap_connect(ld, NULL);
75 if(retVal == LDAP_SUCCESS)
76 printf("ldap_connect succeeded \n");
79 printf("ldap_connect failed with 0x%x.\n",retVal);
80 return 1;
83 // Perform a SASL EXTERNAL bind. The CN of your client certificate
84 // will be your service's UUSID
85 retVal = ldap_sasl_bind_s(ld, "", "EXTERNAL" , &cred, NULL, NULL, &servercredp);
87 if(retVal != LDAP_SUCCESS)
88 printf("ldap_sasl_bind_s failed with 0x%x\n", retVal);
90 printf("ldap_sasl_bind_s succeeded\n");
92 // Search for a person by UUPID
93 retVal = ldap_search_s(ld, base, LDAP_SCOPE_SUBTREE, filter, NULL, NULL, &result);
95 if(retVal != LDAP_SUCCESS)
96 printf("ldap_search_s failed with 0x%x.\n",retVal);
98 // Get the first entry and its DN
99 entry = ldap_first_entry(ld, result);
100 dn = ldap_get_dn(ld, entry);
102 // Print out all viewable attributes for the person
103 if(entry != NULL)
105 char *attribute;
106 BerElement *ber;
107 char **values;
109 for(attribute = ldap_first_attribute(ld, entry, &ber);
110 attribute != NULL;
111 attribute = ldap_next_attribute(ld, entry, ber))
113 if((values = ldap_get_values(ld, entry, attribute)) != NULL)
115 for(int i = 0; values[i] != NULL; i++)
117 printf("%s: %s\n", attribute, values[i]);
124 if(ber != NULL)
126 ber_free(ber, 0);
132 // Determine if the person has the specified affiliation
133 retVal = ldap_compare_s(ld, dn, cmpAttr, cmpVal);
135 if(retVal != LDAP_COMPARE_TRUE)
136 printf("ldap_compare_s failed with 0x%x.\n",retVal);
138 printf("\n%s == %s", cmpAttr, cmpVal);
142 return 0;
Feb 13, 2006 09:56 AM|amarsas|LINK
I finally got .NET 2.0 framework and V Studio 2005. I tried working with the System.DirectoryServices.Protocols class, but it is so different. It has so many options. I think i may be able to figure out a way to do that SASL bind. But, could u please post
an example code snippet if you have one ready. That will save me a lot of time of monkeying around. Also, i have posted a winldap code snippet in my earlier reply. That is exactly what i want to achieve using .NET. PLease let me know.
Thanks in Advance.
Feb 14, 2006 10:02 AM|dunnry|LINK
Feb 23, 2006 01:15 PM|dunnry|LINK
Feb 24, 2006 02:26 PM|amarsas|LINK
Thank you so much Dunnry for posting the example code.
I converted that code to VB.net and am using it. But, it fails at the line
_connect.SessionOptions.SaslMethod = "EXTERNAL";
The error code returned is "86" and the error is:
System.DirectoryServices.Protocols.LdapException: An unknown authentication error occurred. at System.DirectoryServices.Protocols.ErrorChecking.CheckAndSetLdapError(Int32 error) at System.DirectoryServices.Protocols.LdapSessionOptions.SetStringValueHelper(LdapOption
option, String value) at System.DirectoryServices.Protocols.LdapSessionOptions.set_SaslMethod(String value)
Of course, the above is for a Vb.NET code, but i believe it will throw the same exception no matter what programming language you use.
Second thing is, why are we doing a BASIC type authentication as Authtype.Basic in the Ldap connection?
i am able to open the machine certificate store and return the appropriate certificate for authentication.
So the only bottleneck right now seems to be the SASL external bind which is failing as above. And then i will use the Bind() method on the Ldapconnection object once we are through with the SASL sessionoption. Then i will be able to tell you if it doea
Cn you please shed some light. Thanks in advance.
Feb 27, 2006 01:08 PM|dunnry|LINK
Feb 28, 2006 12:02 PM|amarsas|LINK
Thanks again Dunnry. But i do not think it is a client certificate problem. Here is the code that i have in VB.NET
connect.SessionOptions.ProtocolVersion = 3
' I know that the client certificate for i=0 is the one that i need to use
If i = 0 Then
cert = x
i = i + 1
If (cert.SerialNumber <> 0)
In the above code "PrintSearchResponse(searchResponse)" is a function that just prints the number of search results, attributes and their values.
Now, the above code works fine and returns attributes and values that public can view when i comment OUT the
" connect.SessionOptions.SaslMethod =
"External"" line.What happens is that the application connects anonymously to the directory service and hence is able to pull the public data. But as i said, to view authorized data i need to connect using SASL External bind to
the directory. Once i connect using this bind then the directory will identify my application as an authorized connection and display me the authorized attributes too.
I know for a fact that the client certificate works fine because when i comment out the sasl method statement and run the code which returns attribute & values, then schannel shows me server client handshake success messages. It displays message like "An
SSL client handshake completed successfully. The negotiated cryptographic parameters are as follows............etc..."
But when i do not comment out and infact use the statement above, schannel does not show any messages because the connect.Bind() code statement is not run ever since it fails at the earlier statement (which is the saslmethod statement) with this LDAP exception
"An unknown authentication error occurred"
Please help me with the SaslMethod() statement.Why does it keep on failing there? Are we using some wrong value, should we be using some other value?
Thanks in advance!
Feb 28, 2006 12:34 PM|dunnry|LINK
Mar 03, 2006 08:59 AM|amarsas|LINK
Thank you again Dunnry for keeping up with me. Sorry it took so long to get back to you on this. I was working on another project which had some fixes to be done.
I tried the case sensitive nature of EXTERNAL using almost all possible combinations. But sorry no use. Also, LDP tool does not give me that attribute you mentioned. But i am positive that it must be all caps, because on the examples mentioned on my university
website they have it that way.
I tried running your example exactly as it is on my server (except changed the LDAP path to reflect my path "id.directory.a.edu:636" and also tried without the :636. But it fails at the same line of SessionOptions.SaslMethod with the followinf error:
Unhandled Exception: System.DirectoryServices.Protocols.LdapException: An unknow
n authentication error occurred.
(LdapOption option, String value)
at Ldap1Console.LdapSasl..ctor(String server)
May 02, 2007 11:08 PM|kanu|LINK
Did you get a solution for LDAP SASL? I am having exactly same problem and I cant figure out how to fix it. I am also working in university environment and trying to connect to university LDAP Server, they have given a client certificate. The script which
is posted is loading up the certificate, but it fails at connect.bind() statement and gives error as below:-
[LdapException: The LDAP server is unavailable.]
System.DirectoryServices.Protocols.LdapConnection.BindHelper(NetworkCredential newCredential, Boolean needSetCredential) +217
Thanks for your help.
May 03, 2007 10:00 AM|amarsas|LINK
Unfortunately i did not get a solution to that error message. What happened finally was that the university central computing department who managed the ldap servers created a proxy web address for me to use. I used the httprequest and response objects of
asp.net to run my ladp queries using this proxy web address. I do have to provide the digital certificate everytime i send an ldap request though.
Hope this helps. PLease let me know if you do find a solution to that exception.
May 07, 2007 02:09 AM|kanu|LINK
Thanks. Is it possible to send part of your code which does the authentication by email.
Also, is it possible to get some more information on the proxy server.
May 29, 2007 11:27 AM|amarsas|LINK
The university provides a seperate directory for the authentication purposes and for data retrieval purposes. For simple username and pwd authentications we use the authentication directory and not the other proxy that
is only used if we need to fetch more personal information for an individual. An example for a proxy for the directory to fetch detailed information is
For simple authentication we do not use the above proxy, instead we connect to the authentication directory using the
System.DirectoryServices namespace in .NET. Here's a sample code for authentication