首页 > 解决方案 > 如何使用 Novell.Directory.Ldap.NETStandard 和 Simple Paged Results 控件在 Ldap 服务器上进行分页搜索?

问题描述

我正在尝试使用 Novell.Directory.Ldap.NETStandard ( https://github.com/dsbenghe/Novell.Directory.Ldap.NETStandard ) 和简单分页结果控件 ( https:// ldapwiki.com/wiki/Simple%20Paged%20Results%20Control)。

第一页工作正常,但第二页在 searchResult.next() 行上抛出“不可用的关键扩展”。在查看 ActiveDirectory 的事件日志时,我发现:

00000057:LdapErr:DSID-0C090809,注释:错误处理控制,数据 0,v23f0 0000208D:NameErr:DSID-03100213,问题 2001 (NO_OBJECT),数据 0,最佳匹配:

我们也尝试过 LdapVirtualListControl,但遇到了不同的问题,请参阅如何使用 Novell.Directory.Ldap.NETStandard 在具有 > 10000 个条目的 Ldap 服务器上进行分页搜索?

这是我们用来重现的简化代码:

        // Connection
        var ldapConn = new LdapConnection()
        {
            SecureSocketLayer = true,
        };
        ldapConn.UserDefinedServerCertValidationDelegate += (sender, certificate, chain, sslPolicyErrors) => true;
        ldapConn.Connect(host, 636);
        ldapConn.Bind(username, password);

        // Constraints
        LdapSearchConstraints searchConstraints = (LdapSearchConstraints)_conn.SearchConstraints.Clone();
        int pageSize = 100, count = 0;
        bool exit = false;
        const string LDAP_SERVER_SIMPLE_PAGED_RESULT_OID = "1.2.840.113556.1.4.319";

        LdapControl pageControl = null;

        do
        {
            int inPageCount = 0;

            // Add Simple Paged Result control
            var request = new Asn1Sequence(2);
            request.add(new Asn1Integer(pageSize));
            request.add(pageControl == null ? new Asn1OctetString("") : new Asn1OctetString(pageControl.getValue()));
            searchConstraints.setControls(
                new LdapControl(LDAP_SERVER_SIMPLE_PAGED_RESULT_OID, true, request.getEncoding(new LBEREncoder()))
            );

            // Get search result
            var searchResult = (LdapSearchResults)ldapConn.Search(container, LdapConnection.SCOPE_SUB, query, null, false, searchConstraints);
            while (searchResult.hasMore())
            {

                // Detect simple paged result control
                pageControl = searchResult.ResponseControls?.Where(rc => rc.ID == LDAP_SERVER_SIMPLE_PAGED_RESULT_OID).FirstOrDefault();
                if (pageControl != null) break;

                var nextEntry = searchResult.next();
                inPageCount++;

            }
            count += inPageCount;

            // Exit if no more pages
            exit = pageControl == null;

        } while (!exit);

标签: c#.net-coreactive-directoryldap

解决方案


为什么代码不起作用

根据RFC Simple Paged Results Control 编码为

realSearchControlValue ::= SEQUENCE { size INTEGER (0..maxInt), -- requested page size from client -- result set size estimate from server cookie OCTET STRING } 在下一个屏幕截图中可以清楚地看到(取自 Wireshark)。

当客户端向请求添加控制时,大小设置为页面中所需的元素数量,cookie是来自先前服务器响应的不透明结构(第一个请求为空)。

当您尝试在请求中构造控件时,您错误地添加了整个控件值而不是 cookie (pageControl.getValue()):

 var request = new Asn1Sequence(2);
 request.add(new Asn1Integer(pageSize));
 request.add(pageControl == null ? new Asn1OctetString("") : new Asn1OctetString(pageControl.getValue()));

它使第一个请求之后的所有请求都不正确。

建议的解决方案

看看https://github.com/metacube/PagedResultsControl。我创建了封装解码/编码逻辑的类型化简单分页结果控制实现。在来自 Active Directory 的 100 000 多个条目的情况下,对我来说工作得很好。

测试应用程序显示基本用法。


推荐阅读