Novell LDAP C# - Novell.Directory.Ldap - Has anybody made it work?
Asked Answered
C

8

14

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.

Collusive answered 22/12, 2008 at 18:36 Comment(1)
The usual way to get SSL working is to get the signing CA's public key into the equivalent of the Java keystore (Usually a tree CA). Dunno what that means in C# though. Once you have it then all server certificates signed by that tree CA will work. So you would need one per tree.Myrta
C
4

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.

Collusive answered 13/1, 2009 at 21:54 Comment(1)
This looks like it might be helpful to me, but I can't tell because I can't find a running Novell server that has the library. Any chance you could email it to me? chrisfant at G mailCraver
C
8

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;
        }
Carlock answered 6/12, 2012 at 14:38 Comment(0)
A
5

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.

Augustinaaugustine answered 3/6, 2021 at 9:25 Comment(0)
F
4

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).

Flann answered 22/12, 2008 at 18:59 Comment(0)
C
4

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.

Collusive answered 13/1, 2009 at 21:54 Comment(1)
This looks like it might be helpful to me, but I can't tell because I can't find a running Novell server that has the library. Any chance you could email it to me? chrisfant at G mailCraver
F
3

I work on Forefront Identity Manager integration. So the code I write always comes from a few calling clients. This may not be appropriate if you are trying to package an application for use "anywhere".

I just wanted to update this thread with a simple solution for Novell servers which have the default TLS/SSL "confidentiality required" option enabled.

1) Make sure you get the SSL certificates off the Novell server you are binding too and enroll those into the trusted store on the executing client / server. There are normally two 1 for the IP and for the hostname dependent on which you will call (DNS preferable)

2) Import the following / add references using System.DirectoryServices; using System.DirectoryServices.Protocols;

3) Here is a snippet. Make sure you choose the AuthenticationTypes.SecureSocketsLayer which is key.

// serverAddress = Server IP or DNS (Match SSL certificate)
// ObjectDN = The DN of the user you are binding to
// userName = Account which will be used to make the bind
// password = password of the user which will make the bind
// value = The value you wish to add to the attribute

// Connect to the user in LDAP
DirectoryEntry entry = new DirectoryEntry("LDAP://" + serverAddress + "/" + ObjectDN + ""
                , userName
                , password
                , AuthenticationTypes.SecureSocketsLayer);
// Write the Updated attribute
entry.Properties["attribute"].Value = value;
// Read back the updated Attribute into a label
label.Text = entry.Properties["attribute"].Value.ToString();
Fusco answered 26/9, 2013 at 10:57 Comment(0)
M
2

I think I may have already offered this answer to someone else in a different question.

[OtherQuestion on LDAP][1]

Two issues I think: 1) What kind of bind are you trying to do? SSL? Clear text? Anonymous?

2) How is it configured on the eDirectory side for LDAP binds?

The tool LDAP Browser, are you referring to the one at this link? Free LDAP Browser

On the eDirectory side, they can require TLS for all LDAP communication, and they can disallow Anonymous binds.

Can you ask the folks at the other end to enable LDAP tracing (Using DStrace with the +LDAP option enabled, some links for how to use Dstrace on Novell eDirectory look at: Different types of Dstrace Capturing and understand DS Trace for Identity Manager.)

That usually will show an error message that will enlighten you.

My guess is either Require TLS is enabled, and you might not be doing a successful SSL bind.

If so, try to connect on port 636, with SSL enabled, and a fully qualified DN for the user you are trying to login as.

If you are trying with SSL enabled, and you are not getting a pop up box about accepting the tree CA's trusted root certficate, then perhaps the CA or the SSL certificate taht the eDirectory server is user has expired or is broken. (There are any number of causes for this that can be common, and take but a moment to fix).

Usually in Dstrace you will see an error about the SSL certificate if there is a problem. An example from a Novell Identity Manager perspective of an expired certificate is in this article: Certificate Expired As well as some details on how to fix the certificates.

Next possibility is that the DN you are specifying is not quite correct.

Let me know if you need more help.

Myrta answered 22/12, 2008 at 19:4 Comment(2)
We cant change anything on the Novell server, its managed by another team and running in a live environment. So we have a connection acces to test the authentication with it, but that's all we have. With the LDAP browser we are able to connect to it, so its a matter of making this DLL work.Collusive
Do you have the tree roots certificate in your Keystore? (Not sure what the C# equivalent is called). It is not server specific, per se. It is more tree specific. I.e. One root CA cert per tree will allow access to all servers.Myrta
F
1

Following my previous post - if you have to use secure connection, try to use ldaps:// as a prefix to server address.

If there is no SSL/TLS support, you can try this - guidelines and .NET wrapper for OpenLDAP library.

One important point - there are settings for TLS security level in OpenLDAP, so if your LDAP server has self-signed certificate you either have to import it on a client side or set TLS to not check the signing authority *that is less secure of course).

Flann answered 23/12, 2008 at 16:33 Comment(2)
Adding ldaps:// make the address invalid. The server uses SSL and the certificate is imported on the client-side.Collusive
And the OpenLDAP library is made with an Visual Studio and there is no compiled version (its dating from before 2004).Collusive
M
1

I had gone through this scenario, for me Novell LDAP service running in Kubernetes container. I tried adding CA certificate to the Mono trust store, which will add the file inside "/usr/share/.mono/certs/Trust" in linux container. But nothing did work, still Novell connect not successful for LDAP 636 port.

Finally I made it work in below way:

LdapConnection Connection = new LdapConnection();
    Connection.SecureSocketLayer = true;
    Connection.UserDefinedServerCertValidationDelegate += new
            Novell.Directory.Ldap.RemoteCertificateValidationCallback(LdapSSLHandler);

    public bool LdapSSLHandler(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certificate, System.Security.Cryptography.X509Certificates.X509Chain chain,
                  System.Net.Security.SslPolicyErrors sslPolicyErrors)
    {
        if (sslPolicyErrors == sslPolicyErrors.None)
        {
            return true;   //Is valid
        }

        if (certificate.GetCertHashString() == "YOUR CERTIFICATE HASH KEY") // Thumbprint value of the certificate
        {
            return true;
        }

        return false;
    }
Metamorphose answered 4/9, 2019 at 7:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.