Novell LDAP C# - Novell.Directory.Ldap - 有人成功使用过吗?

14

我正在尝试使用Novell发布的库(Novell.Directory.Ldap),版本为2.1.10。

到目前为止,我已经完成了以下工作:

  • 我使用一个应用程序(LdapBrowser)测试了连接,它可以正常工作,因此不是通信问题。

  • 它在Mono中编译,但我正在使用Visual Studio。因此,我使用源代码创建了一个项目。我还包括对Mono.Security的引用,因为该项目依赖于它。

  • 我在连接的错误捕获部分注释了一个调用(freeWriteSemaphore(semId);),因为它会抛出更多异常。我检查了这个调用的作用,发现它只是一个错误跟踪机制。

  • 我遵循了Novell提供的文档中提供的基本步骤(http://www.novell.com/coolsolutions/feature/11204.html)。

    // 创建LdapConnection实例

    LdapConnection ldapConn = new LdapConnection(); ldapConn.SecureSocketLayer = ldapPort == 636;

    // Connect函数将创建到服务器的套接字连接

    ldapConn.Connect(ldapHost,ldapPort);

    // Bind函数将用户对象凭据绑定到服务器

    ldapConn.Bind(userDN,userPasswd);

  • 现在它在Bind()函数处崩溃。我收到错误91。

那么,有人使用过这个库并看到它起作用了吗?如果是这样的话,你是如何使其工作的?是否需要一些特殊的配置?有没有办法在.NET环境中让它工作而不需要Mono(我可以引用Mono dlls,但我不想在服务器上安装它)?

(更新) 连接在端口636上,因此使用SSL。我用WireShark检查了通信并与LDAP Browser得到的结果进行了比较。我发现LDAP库没有执行SSL证书通信步骤。那么,最好的方法是让它做它应该做的事情是什么?

(更新)我查阅了文档,它指出它不支持SSL。http://www.novell.com/coolsolutions/feature/11204.html

使用LdapConnection.Bind()验证到LDAP服务器。我们只支持明文身份验证。SSL/TLS支持尚未添加。

但是,该文档的日期是2004年,自那时以来进行了许多更新。而且库中有一个参数可以定义连接是否使用SSL。所以现在我很困惑。

(更新)找到了更加最新的文档:http://developer.novell.com/documentation//ldapcsharp/index.html?page=/documentation//ldapcsharp/cnet/data/bqwa5p0.html。SSL连接的建立方式是在服务器上注册证书。问题在于我所做的不限于特定的Novell服务器,因此证书必须动态获取。


让 SSL 正常工作的通常方法是将签署 CA 的公钥获取到 Java 密钥库的等效位置中(通常是树形结构的 CA)。不过在 C# 中这是什么意思我不太清楚。一旦您拥有了它,那么由该树形 CA 签署的所有服务器证书都将有效。因此,每个树形结构需要一个。 - geoffc
8个回答

8

我曾经遇到和你类似的问题,我的绑定命令也会失败,而且我使用了来自Novell网站的相同代码。对我起作用的解决方案是添加一个动态证书验证回调函数。你可以在这里阅读相关信息

        // 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;
        }

5

UserDefinedServerCertValidationDelegate已过时,如果出现无效的SSL证书问题,可以通过以下方式跳过证书验证:

        LdapConnectionOptions options = new LdapConnectionOptions()
            .ConfigureRemoteCertificateValidationCallback(new CertCallback((a, b, c, d) => true))
            .UseSsl();

        LdapConnection connection = new LdapConnection(options);

        connection.Connect(...);
       

然而,您应该审查忽略证书是否是您的应用程序的安全解决方案。


4

91是“无法连接”的意思。尝试将服务器格式设置为“ldap://x.x.x.x”,检查userDN是否正确设置(包括域等)。

我经常使用WireShark来查看网络层面上发生的情况(它可以识别LDAP协议)。


4
我终于找到了一种方法使这个工作起来了。
首先,这些帖子帮助了我找到了正确的方向:http://directoryprogramming.net/forums/thread/788.aspx 其次,我获取了Novell LDAP Library的编译后的dll,并使用了Mono.Security.Dll。
解决方案:
我将以下函数添加到了代码中。
// 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;
        }

我在绑定过程中使用了它。

// 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;

关键要素是使用SSL处理程序动态获取证书,并使用X509StoreManager.LocalMachine,以便在网站运行时保存和获取证书。

这似乎对我有所帮助,但我无法确定,因为我找不到一个运行Novell服务器的库。您能否通过电子邮件将其发送给我?chrisfant at G mail - Fantius

3
我在负责 Forefront Identity Manager 集成,所以我写的代码总是来自于几个调用客户端。如果您想要打包一个可在任何地方使用的应用程序,这可能不太合适。
我只是想用一种简单的方法更新这个主题,解决默认启用传输层安全/安全套接层 (TLS/SSL) "保密性必需" 选项的 Novell 服务器的问题。
1)确保从您正在绑定的 Novell 服务器获取 SSL 证书,并将其登记到执行客户端/服务器的受信任存储中。通常有两个证书,一个是基于 IP 的证书,另一个是基于主机名的证书(DNS 优先)。
2)导入以下内容/添加引用 using System.DirectoryServices; using System.DirectoryServices.Protocols;
3)这里是一段示例代码。请确保选择 AuthenticationTypes.SecureSocketsLayer 选项。
// 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();

2
我想我可能已经在另一个问题中向其他人提供了这个答案。
LDAP的其他问题
我认为有两个问题:1)您正在尝试进行什么样的绑定? SSL?明文?匿名?
2)在eDirectory方面,LDAP绑定如何配置?
LDAP浏览器工具,您是指此链接上的那个吗? 免费LDAP浏览器
在eDirectory方面,他们可以要求所有LDAP通信都使用TLS,并且可以禁止匿名绑定。
您能否请对方启用LDAP跟踪(使用启用+LDAP选项的DStrace,一些关于如何在Novell eDirectory上使用Dstrace的链接,请查看:不同类型的Dstrace捕获和理解身份管理器的DS跟踪。)
通常,这将显示一个错误消息,使您恍然大悟。
我猜测要么启用了Require TLS,您可能没有成功的进行SSL绑定。
如果是这样,请尝试使用启用SSL的636端口连接,并使用完全限定的DN登录您要登录的用户。
如果您尝试启用SSL,并且没有弹出关于接受树CA的受信任根证书的框,那么可能是CA或eDirectory服务器使用的SSL证书已过期或损坏。(这可能有很多原因,但只需花费一点时间即可修复)。
通常在Dstrace中,如果存在问题,您将看到有关SSL证书的错误。从Novell Identity Manager角度来看,一个过期证书的示例在本文中:Certificate Expired,以及一些有关如何修复证书的详细信息。
下一个可能性是您指定的DN不完全正确。
如果需要更多帮助,请告诉我。

我们无法更改Novell服务器上的任何内容,它由另一个团队管理并在生产环境中运行。因此,我们只能通过连接来测试身份验证,但这就是我们所拥有的一切。使用LDAP浏览器,我们可以连接到它,所以问题在于让这个DLL起作用。 - ceetheman
你的Keystore中是否有树根证书?(不确定C#的等效物叫什么)。它并不是特定于服务器的。更确切地说,它是特定于树的。也就是说,每棵树只需要一个根CA证书即可访问所有服务器。 - geoffc

1

接下来是我之前发布的帖子 - 如果您必须使用安全连接,请尝试在服务器地址前使用ldaps://作为前缀。

如果没有SSL/TLS支持,您可以尝试this - OpenLDAP库的指南和.NET封装。

一个重要的问题 - 在OpenLDAP中有TLS安全级别设置,如果您的LDAP服务器具有自签名证书,则必须在客户端导入该证书或将TLS设置为不检查签名颁发机构(这当然更不安全)。


添加 ldaps:// 会使地址无效。服务器使用 SSL,证书已在客户端导入。 - ceetheman
OpenLDAP库是使用Visual Studio制作的,没有编译版本(它的日期早于2004年)。 - ceetheman

1
我曾经遇到过这种情况,我的Novell LDAP服务运行在Kubernetes容器中。我尝试将CA证书添加到Mono信任存储中,这将在Linux容器中的“/usr/share/.mono/certs/Trust”文件夹中添加该文件。但是仍然无法正常连接LDAP 636端口。
最终我通过以下方式解决了问题:
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;
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接