c# - 检查 AD 组是否是另一个组的成员(递归)
问题描述
想象一下我有结构
RootGroup <- Group{x} .... <- Group{x+n} <- Group100
我怎么能检查那Group100
是成员RootGroup
我有这个,它总是返回false
private bool IsMemberOfInternal(string userOrGroupDistinguishedName, string groupMembershipDistinguishedName)
{
GroupPrincipal principal = null;
GroupPrincipal target = null;
try
{
principal = _getUserGroupPrincipalFunc(principalContext, userOrGroupDistinguishedName);
target = _getUserGroupPrincipalFunc(principalContext, groupMembershipDistinguishedName);
if (principal != default(GroupPrincipal)
&& target != default(GroupPrincipal))
{
return principal.IsMemberOf(target);
}
}
catch
{
}
return false;
}
解决方案
你最好不要使用GroupPrincipal
这个。AD 实际上有一个内置的方法来做这种搜索,它比任何事情GroupPrincipal
都快得多。您可以通过使用DirectoryEntry
andDirectorySearcher
直接使用它(无论如何,这就是GroupPrincipal
幕后PrincipalSearcher
使用的内容)。
我写了一篇关于确定用户是否是特定组的成员的文章,但它同样适用于组。我有一个示例方法,您可以使用它:
private static bool IsUserInGroup(DirectoryEntry user, DirectoryEntry group, bool recursive) {
//fetch the attributes we're going to need
user.RefreshCache(new [] {"distinguishedName", "objectSid"});
group.RefreshCache(new [] {"distinguishedName", "groupType"});
//This magic number tells AD to look for the user recursively through any nested groups
var recursiveFilter = recursive ? ":1.2.840.113556.1.4.1941:" : "";
var userDn = (string) user.Properties["distinguishedName"].Value;
var groupDn = (string) group.Properties["distinguishedName"].Value;
var filter = $"(member{recursiveFilter}={userDn})";
if (((int) group.Properties["groupType"].Value & 8) == 0) {
var groupDomainDn = groupDn.Substring(
groupDn.IndexOf(",DC=", StringComparison.Ordinal));
var userDomainDn = userDn.Substring(
userDn.IndexOf(",DC=", StringComparison.Ordinal));
if (groupDomainDn != userDomainDn) {
//It's a Domain Local group, and the user and group are on
//different domains, so the account might show up as a Foreign
//Security Principal. So construct a list of SID's that could
//appear in the group for this user
var fspFilters = new StringBuilder();
var userSid =
new SecurityIdentifier((byte[]) user.Properties["objectSid"].Value, 0);
fspFilters.Append(
$"(member{recursiveFilter}=CN={userSid},CN=ForeignSecurityPrincipals{groupDomainDn})");
if (recursive) {
//Any of the groups the user is in could show up as an FSP,
//so we need to check for them all
user.RefreshCache(new [] {"tokenGroupsGlobalAndUniversal"});
var tokenGroups = user.Properties["tokenGroupsGlobalAndUniversal"];
foreach (byte[] token in tokenGroups) {
var groupSid = new SecurityIdentifier(token, 0);
fspFilters.Append(
$"(member{recursiveFilter}=CN={groupSid},CN=ForeignSecurityPrincipals{groupDomainDn})");
}
}
filter = $"(|{filter}{fspFilters})";
}
}
var searcher = new DirectorySearcher {
Filter = filter,
SearchRoot = group,
PageSize = 1, //we're only looking for one object
SearchScope = SearchScope.Base
};
searcher.PropertiesToLoad.Add("cn"); //just so it doesn't load every property
return searcher.FindOne() != null;
}
此方法还处理user
(或您的子组)位于根组的外部受信任域上的情况。这可能是也可能不是您必须担心的事情。
只需将 a作为参数传递DirectoryEntry
给您。像这样的东西:Group100
user
var isMemberOf = IsUserInGroup(
new DirectoryEntry($"LDAP://{userOrGroupDistinguishedName}"),
new DirectoryEntry($"LDAP://{groupMembershipDistinguishedName}"),
true);
true
对于递归搜索(当您传递recursive
参数时),它使用LDAP_MATCHING_RULE_IN_CHAIN
“匹配规则 OID”(如此处所述):
此规则仅限于适用于 DN 的过滤器。这是一个特殊的“扩展”匹配运算符,它将对象中的祖先链一直遍历到根,直到找到匹配项。
推荐阅读
- php - 如何链接到页面的特定部分 HTML PHP
- c# - 当后端代码中的简单键值变量工作相同时,为什么要使用 redis 作为缓存层?
- google-apps-script - Google Slides Apps 脚本检索页面中的形状
- python-3.x - 在 KNeighborsClassifier 中使用自定义指标时,我不断收到“TypeError:只有整数标量数组可以转换为标量索引”
- java - JavaFX - 在使用选项卡时将 GUI 拆分为单独的类
- jquery - 通过函数调整电子窗口大小
- scheme - 匹配方案中的括号
- android - 当我使用 adb 显示 /sys/kernel/debug/tracing/available_filter_functions 时没有这样的设备
- python - 初始化以迭代抽象pyomo模型中的集合?
- angular-cli - 运行 ng serve -o 时出现错误