I'm trying to use the library released by Novell (Novell.Directory.Ldap). Version 2.1.10.
What I've done so far:
I tested the connection with an application (LdapBrowser) and it's working, so its not a communication problem.
It's compiled in Mono, but I'm working with Visual Studio. So created a project with the sources. I also included a reference to Mono.Security, because the project depended on it.
I commented a call (freeWriteSemaphore(semId); ) in the error catching part of the connection, because it was throwing more exceptions. I checked what that call did, and its just a error tracing mechanism.
I followed the basics steps provided in the documentation by Novell (http://www.novell.com/coolsolutions/feature/11204.html).
// Creating an LdapConnection instance
LdapConnection ldapConn= new LdapConnection(); ldapConn.SecureSocketLayer = ldapPort == 636;
//Connect function will create a socket connection to the server
ldapConn.Connect(ldapHost,ldapPort);
//Bind function will Bind the user object Credentials to the Server
ldapConn.Bind(userDN,userPasswd);
Right now it's crashing at the Bind() function. I get the error 91.
So, has someone ever used this library and seen it work? If so, what did you do to make it work, is there some special configuration needed? Is there a way to make it work in .NET environment without Mono (I can have references to Mono dlls, but I don't want it to be installed on the server)?
(UPDATE) The connection is on port 636, thus using SSL. I checked with WireShark the communication and compared with what I get from LDAP Browser. I've seen that the step where the SSL certicate is communicated, is not done by the LDAP library. So, what is the best way to make it do what its supposed to?
(UPDATE) I checked the documentation and it's indicating that it doesn't support SSL. http://www.novell.com/coolsolutions/feature/11204.html
Authenticate to the LDAP server with LdapConnection.Bind(). We support only cleartext authentication. SSL/TLS support is yet to be added.
But the documentation date from 2004, and since then, many updates have been made. And there is a parameter in the library to define if the connection uses SSL. So now I'm confused.
(UPDATE) Found a more up-to-date documentation : http://developer.novell.com/documentation//ldapcsharp/index.html?page=/documentation//ldapcsharp/cnet/data/bqwa5p0.html. The way the SSL connection is made, is by registering the certificate on the server. The problem is that what I'm doing is not bound to a specific Novell server, so the certificate must be obtained dynamically.
This is clearly a question about LDAP (the protocol which should allow a C# client to talk to a Novell server) and its authentication methods. If you can get access to the eDirectory servers logs and ask them to enable +LDAP tracing, then a bind attempt that fails could provide additional interesting information.
GitHub - dsbenghe/Novell.Directory.Ldap.NETStandard: LDAP client library for .NET Standard 1.3 up to 2.1 and NET5 - works with any LDAP protocol compatible directory server (including Microsoft Active Directory). Failed to load latest commit information.
The central class that encapsulates the connection to a directory server through the Ldap protocol. LdapConnection objects are used to perform common Ldap operations such as search, modify and add. In addition, LdapConnection objects allow you to bind to an Ldap server, set connection and search constraints, and perform several other tasks.
The LDAP libraries provide access to NetIQ eDirectory based on the C LDAP API, which is based on the draft proposed to the IETF. Portions of the source for this component are also based on the Directory SDK (Version 2.0), which is available from OpenLDAP .
The UserDefinedServerCertValidationDelegate is obsolete, so if it is an issue with invalid ssl certificates, you can skip the certificatevalidaion this way:
LdapConnectionOptions options = new LdapConnectionOptions()
.ConfigureRemoteCertificateValidationCallback(new CertCallback((a, b, c, d) => true))
.UseSsl();
LdapConnection connection = new LdapConnection(options);
connection.Connect(...);
You should however review if ignoring the certificate is a secure solution for your application.
I came looking for a solution to a similar problem. My bind command would fail as well while using the same code from Novell's website. The solution that worked for me was adding a dynamic Certificate Validation Call back. You can read about it here.
// Creating an LdapConnection instance
LdapConnection ldapConn = new LdapConnection();
ldapConn.SecureSocketLayer = true;
ldapConn.UserDefinedServerCertValidationDelegate += new
CertificateValidationCallback(MySSLHandler);
//Connect function will create a socket connection to the server
ldapConn.Connect(ldapHost, ldapPort);
//Bind function will Bind the user object Credentials to the Server
ldapConn.Bind(userDN, userPasswd);
// Searches in the Marketing container and return all child entries just below this
//container i.e. Single level search
LdapSearchResults lsc = ldapConn.Search("ou=users,o=uga",
LdapConnection.SCOPE_SUB,
"objectClass=*",
null,
false);
while (lsc.hasMore())
{
LdapEntry nextEntry = null;
try
{
nextEntry = lsc.next();
}
catch (LdapException e)
{
Console.WriteLine("Error: " + e.LdapErrorMessage);
// Exception is thrown, go for next entry
continue;
}
Console.WriteLine("\n" + nextEntry.DN);
LdapAttributeSet attributeSet = nextEntry.getAttributeSet();
System.Collections.IEnumerator ienum = attributeSet.GetEnumerator();
while (ienum.MoveNext())
{
LdapAttribute attribute = (LdapAttribute)ienum.Current;
string attributeName = attribute.Name;
string attributeVal = attribute.StringValue;
Console.WriteLine(attributeName + "value:" + attributeVal);
}
}
ldapConn.Disconnect();
Console.ReadKey();
}
public static bool MySSLHandler(Syscert.X509Certificate certificate,
int[] certificateErrors)
{
X509Store store = null;
X509Stores stores = X509StoreManager.CurrentUser;
//string input;
store = stores.TrustedRoot;
X509Certificate x509 = null;
X509CertificateCollection coll = new X509CertificateCollection();
byte[] data = certificate.GetRawCertData();
if (data != null)
x509 = new X509Certificate(data);
return true;
}
I finally found a way to make this work.
First, theses posts helped me get on the right track : http://directoryprogramming.net/forums/thread/788.aspx
Second, I got a compiled dll of the Novell LDAP Library and used the Mono.Security.Dll.
The solution:
I added this function to the code
// This is the Callback handler - after "Binding" this is called
public bool MySSLHandler(Syscert.X509Certificate certificate, int[] certificateErrors)
{
X509Store store = null;
X509Stores stores = X509StoreManager.LocalMachine;
store = stores.TrustedRoot;
//Import the details of the certificate from the server.
X509Certificate x509 = null;
X509CertificateCollection coll = new X509CertificateCollection();
byte[] data = certificate.GetRawCertData();
if (data != null)
x509 = new X509Certificate(data);
//List the details of the Server
//if (bindCount == 1)
//{
Response.Write("<b><u>CERTIFICATE DETAILS:</b></u> <br>");
Response.Write(" Self Signed = " + x509.IsSelfSigned + " X.509 version=" + x509.Version + "<br>");
Response.Write(" Serial Number: " + CryptoConvert.ToHex(x509.SerialNumber) + "<br>");
Response.Write(" Issuer Name: " + x509.IssuerName.ToString() + "<br>");
Response.Write(" Subject Name: " + x509.SubjectName.ToString() + "<br>");
Response.Write(" Valid From: " + x509.ValidFrom.ToString() + "<br>");
Response.Write(" Valid Until: " + x509.ValidUntil.ToString() + "<br>");
Response.Write(" Unique Hash: " + CryptoConvert.ToHex(x509.Hash).ToString() + "<br>");
// }
bHowToProceed = true;
if (bHowToProceed == true)
{
//Add the certificate to the store. This is \Documents and Settings\program data\.mono. . .
if (x509 != null)
coll.Add(x509);
store.Import(x509);
if (bindCount == 1)
removeFlag = true;
}
if (bHowToProceed == false)
{
//Remove the certificate added from the store.
if (removeFlag == true && bindCount > 1)
{
foreach (X509Certificate xt509 in store.Certificates)
{
if (CryptoConvert.ToHex(xt509.Hash) == CryptoConvert.ToHex(x509.Hash))
{
store.Remove(x509);
}
}
}
Response.Write("SSL Bind Failed.");
}
return bHowToProceed;
}
And i used it in the binding process
// Create Connection
LdapConnection conn = new LdapConnection();
conn.SecureSocketLayer = true;
Response.Write("Connecting to:" + ldapHost);
conn.UserDefinedServerCertValidationDelegate += new
CertificateValidationCallback(MySSLHandler);
if (bHowToProceed == false)
conn.Disconnect();
if (bHowToProceed == true)
{
conn.Connect(ldapHost, ldapPort);
conn.Bind(loginDN, password);
Response.Write(" SSL Bind Successfull ");
conn.Disconnect();
}
quit = false;
The key elements are using the SSL Handler to dynamically obtain the Certificate, and using X509StoreManager.LocalMachine so that when the website is running its able to save and fetch the certificates.
91 is "cannot connect". Try to put the server in "ldap://x.x.x.x" format, check that userDN is set properly (with domain etc).
I am often using WireShark to see what is going on at the network level (it is aware of LDAP protocol).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With