使用 Novell LDAP 针对 .NET Core 中的 AD 进行页面 LDAP 查询

Page LDAP query against AD in .NET Core using Novell LDAP

我正在使用 Novell LDAP 库从 .NET 代码应用程序查询 Active Directory。大多数查询成功,但有些 return 超过 1000 个结果,AD 服务器拒绝。因此,我试图找出如何使用 Novell 的库对 LDAP 查询进行分页。我放在一起的解决方案看起来像

public IEnumerable<LdapUser> GetUsers() {
    this.Connect();

    try {
        var cntRead = 0;                            // Total users read.
        int? cntTotal = null;                       // Users available.
        var curPage = 0;                            // Current page.
        var pageSize = this._config.LdapPageSize;   // Users per page.

        this.Bind();

        this._logger.LogInformation("Searching LDAP users.");
        do {
            var constraints = new LdapSearchConstraints();

            // The following has no effect:
            //constraints.MaxResults = 10000;

            // Commenting out the following succeeds until the 1000th entry.
            constraints.setControls(GetListControl(curPage, pageSize));

            var results = this._connection.Search(
                this._config.LdapSearchBase,
                this.LdapSearchScope,
                this._config.LdapUsersFilter,
                this.LdapUserProperties,
                false,
                constraints);

            while (results.hasMore() && ((cntTotal == null) || (cntRead < cntTotal))) {
                ++cntRead;

                LdapUser user = null;

                try {
                    var result = results.next();
                    Debug.WriteLine($"Found user {result.DN}.");
                    user = new LdapUser() {
                        AccountName = result.getAttribute(this._config.LdapAccountAttribute)?.StringValue,
                        DisplayName = result.getAttribute(this._config.LdapDisplayNameAttribute)?.StringValue
                    };
                } catch (LdapReferralException) {
                    continue;
                }

                yield return user;
            }

            ++curPage;
            cntTotal = GetTotalCount(results);
        } while ((cntTotal != null) && (cntRead < cntTotal));
    } finally {
        this._connection.Disconnect();
    }
}

并使用以下两个辅助方法:

private static LdapControl GetListControl(int page, int pageSize) {
    Debug.Assert(page >= 0);
    Debug.Assert(pageSize >= 0);
    var index = page * pageSize + 1;
    var before = 0;
    var after = pageSize - 1;
    var count = 0;
    Debug.WriteLine($"LdapVirtualListControl({index}, {before}, {after}, {count}) = {before}:{after}:{index}:{count}");
    return new LdapVirtualListControl(index, before, after, count);
}

private static int? GetTotalCount(LdapSearchResults results) {
    Debug.Assert(results != null);

    if (results.ResponseControls != null) {
        var r = (from c in results.ResponseControls
                 let d = c as LdapVirtualListResponse
                 where (d != null)
                 select (LdapVirtualListResponse) c).SingleOrDefault();
        if (r != null) {
            return r.ContentCount;
        }
    }

    return null;
}   

设置constraints.MaxResults似乎对AD服务器没有影响。如果我不设置LdapVirtualListControl,则检索成功,直到检索到第1000条。

如果我使用 LdapVirtualListControl,操作会在第一次调用 results.next() 时失败,出现以下异常:

System.Collections.Generic.KeyNotFoundException: The given key '76' was not present in the dictionary.
   at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
   at Novell.Directory.Ldap.Utilclass.ResourcesHandler.getResultString(Int32 code, CultureInfo locale)
   at Novell.Directory.Ldap.LdapResponse.get_ResultException()
   at Novell.Directory.Ldap.LdapResponse.chkResultCode()
   at Novell.Directory.Ldap.LdapSearchResults.next()

https://github.com/dsbenghe/Novell.Directory.Ldap.NETStandard/blob/master/src/Novell.Directory.Ldap.NETStandard/Utilclass/ResultCodeMessages.cs 处的代码表明这只是一个后续错误,真正的问题是调用失败,错误代码为 76,我不知道它是什么。因此,我认为我在查询中遗漏了一些东西。那里有什么问题?

我已修复 - 以防其他人遇到此问题:

经过一些互联网研究,我在 https://ldap.com/ldap-result-code-reference-other-server-side-result-codes/#rc-virtualListViewError what error code 76 means and that the LdapVirtualListResponse contains more information. In my case, the error was https://ldap.com/ldap-result-code-reference-other-server-side-result-codes/#rc-sortControlMissing 上找到了 - 看来分页需要一个排序控件。 为了修复它,我添加了

constraints.setControls(new[] {
    new LdapSortControl(new LdapSortKey("cn"), true),
    GetListControl(curPage, pageSize)
});