使用.NET Core 5和Novell.Directory.LDAP.NETStandard从Domino LDAP服



我想从Domino LDAP的一个大位置获取所有用户,总共大约有2000个用户。遗憾的是,由于.NET Core没有一个独立于平台的LDAP库,我将Novell.Directory.LDAP.NETStandard与这个POC:一起使用

var cn = new Novell.Directory.Ldap.LdapConnection();
cn.Connect("dc.internal", 389);
cn.Bind("user", "pw");
string filter = "location=MyLoc";
var result = cn.Search("", Novell.Directory.Ldap.LdapConnection.ScopeOne, filter, new string[] { Novell.Directory.Ldap.LdapConnection.AllUserAttrs }, typesOnly: false);            
int count = 0;
while (result.HasMore()) {
var entry = result.Next();
count++;
Console.WriteLine(entry.Dn);
}

它给我打印了很多条目,但不是全部。当count = 1000时,我得到了一个Size Limit Exceeded异常。我想这是因为我需要使用某种分页,所以不是所有条目都会在一个请求中返回。有不同的问题像这个或这个。在Java中,.NET核心API似乎有所不同。

方法1:尝试了解LdapSearchRequest在.NET Core中的工作方式

byte[] resumeCookie = null;
LdapMessageQueue queue = null;
var searchReq = new LdapSearchRequest("", LdapConnection.ScopeOne, filter, new string[] { LdapConnection.AllUserAttrs },
LdapSearchConstraints.DerefNever, maxResults: 3000, serverTimeLimit: 0, typesOnly: false, new LdapControl[] { new SimplePagedResultsControl(size: 100, resumeCookie) });            
var searchRequest = cn.SendRequest(searchReq, queue);

我正试图弄清楚如何在.NET Core中使用Java示例。这看起来不错,但是我不知道如何获取LDAP条目。我只得到一个消息id。通过查看源代码,我似乎走对了路,但他们使用的是MessageAgent,因为它是internal sealed,所以不能在外部使用。这就是为什么在源代码中搜索LdapRearchRequest不会得到很多结果的原因。

方法2:使用SimplePagedResultsControlHandler

var opts = new SearchOptions("", LdapConnection.ScopeOne, filter, new string[] { LdapConnection.AllUserAttrs });
// For testing purpose: https://github.com/dsbenghe/Novell.Directory.Ldap.NETStandard/issues/163
cn.SearchConstraints.ReferralFollowing = false;
var pageControlHandler = new SimplePagedResultsControlHandler(cn);
var rows = pageControlHandler.SearchWithSimplePaging(opts, pageSize: 100);

这将引发Unavaliable Cricital Extension异常。首先,我认为这是.NET端口的问题,它可能还不支持原始Java库的所有功能。它看起来很完整,根据进一步的研究,它看起来像是一个LDAP错误代码。因此,这一定是服务器必须支持的内容,但Domino不支持。

我无法使其中至少一种方法发挥作用,但找到了另一种方法:在.NET 5中添加了对System.DirectoryServices.Protocols命名空间的跨平台支持。这在.NET Core中已经缺失了很长一段时间,我想这就是像Novell.Directory.Ldap.NETStandard这样的库被移植到.NET Core的主要原因——在.NET Core 1.x时代,这是我发现的唯一一种针对LDAP进行身份验证的方法,LDAP也适用于Linux。

在深入了解System.DirectoryServices.Protocols之后,它开箱即用,甚至适用于约2k用户。我的基本POC类如下:

public class DominoLdapManager {
LdapConnection cn = null;
public DominoLdapManager(string ldapHost, int ldapPort, string ldapBindUser, string ldapBindPassword) {
var server = new LdapDirectoryIdentifier(ldapHost, ldapPort);
var credentials = new NetworkCredential(ldapBindUser, ldapBindPassword);
cn = new LdapConnection(server);
cn.AuthType = AuthType.Basic;
cn.Bind(credentials);
}
public IEnumerable<DominoUser> Search(string filter, string searchBase = "") {
string[] attributes = { "cn", "mail", "companyname", "location" };
var req = new SearchRequest(searchBase, filter, SearchScope.Subtree, attributes);
var resp = (SearchResponse)cn.SendRequest(req);
foreach (SearchResultEntry entry in resp.Entries) {
var user = new DominoUser() {
Name = GetStringAttribute(entry, "cn"),
Mail = GetStringAttribute(entry, "mail"),
Company = GetStringAttribute(entry, "companyname"),
Location = GetStringAttribute(entry, "location")
};
yield return user;
}
yield break;
}
string GetStringAttribute(SearchResultEntry entry, string key) {
if (!entry.Attributes.Contains(key)) {
return string.Empty;
}
string[] rawVal = (string[])entry.Attributes[key].GetValues(typeof(string));
return rawVal[0];
}
}

示例用法:

var ldapManager = new DominoLdapManager("ldap.host", 389, "binduser", "pw");
var users = ldapManager.Search("objectClass=person");

但它并没有像标题所说的那样用Novell.Directory.Ldap.NETStandard来解决

这并不能像标题所建议的那样解决我对Novell.Directory.Ldap.NETStandard库的问题,是的。但由于System.DirectoryServices.Protocols是微软和.NET基金会维护的官方.NET软件包,这对我来说似乎是更好的方式。基金会会会注意保持它的维护,并与.NET的后续版本兼容。当我写这个问题的时候,我没有意识到现在添加了对Linux的支持。

不要误解我的意思,我不想说第三个包在设计上是糟糕的——那将是完全错误的。然而,当我在官方套餐和第三方套餐之间做出选择时,我认为更喜欢官方套餐是有道理的。但有一个很好的理由反对这一点——这里的情况并非如此:官方方案(过去不存在(比第三方方案更能解决这个问题。

最新更新