如何在 .net 中获取 ForeignSecurityPrincipal 对象的详细信息
How to get the details of ForeignSecurityPrincipal object in .net
我有 2 个域 A 和 B。我在 B "GroupInB" 中有一个组,其中有一个用户 "UserInB"(将来,该组中可以有很多用户)。在域A中,我创建了一个组"GroupInA",然后将"GroupInB"添加到"GroupInA"。 (这会导致 GroupB 的 ForeignSecurityPrincipal)。而且我在 "GroupA".
中添加了一个用户 "UserInA"
现在的问题是,我想读取"GroupA"中的所有用户。我希望结果是
- UserInA
- UserInB
但是当尝试从 DirectoryEntry 读取用户时,我得到的只是
- UserInA
- GroupInB
有什么方法可以让我也从 "GroupInB" 获得用户吗? :(
前阵子写了一篇关于获取一个组的所有成员的文章:Find all the members of a group
我包括了关于 finding users from external trusted domains 的部分,它显示为外国安全主体,但我似乎忘记了这个特定的用例:来自外部域的组是其中的成员。所以我更新了文章中的代码并将其包含在下面。
这有点复杂,因为外部安全主体具有外部域上对象的 SID,但要使用 SID 绑定到对象,您必须使用域的 DNS 名称。因此,我们首先需要为所有受信任的域创建域 SID 和 DNS 名称的映射。但是,如果您 运行 仅在一个环境中使用此功能,则始终可以对域列表进行硬编码以加快速度。
这是代码。如果你给recursive
参数传递true
,它会展开所有成员组。
public static IEnumerable<string> GetGroupMemberList(DirectoryEntry group, bool recursive = false, Dictionary<string, string> domainSidMapping = null) {
var members = new List<string>();
group.RefreshCache(new[] { "member", "canonicalName" });
if (domainSidMapping == null) {
//Find all the trusted domains and create a dictionary that maps the domain's SID to its DNS name
var groupCn = (string) group.Properties["canonicalName"].Value;
var domainDns = groupCn.Substring(0, groupCn.IndexOf("/", StringComparison.Ordinal));
var domain = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain, domainDns));
var trusts = domain.GetAllTrustRelationships();
domainSidMapping = new Dictionary<string, string>();
foreach (TrustRelationshipInformation trust in trusts) {
using (var trustedDomain = new DirectoryEntry($"LDAP://{trust.TargetName}")) {
try {
trustedDomain.RefreshCache(new [] {"objectSid"});
var domainSid = new SecurityIdentifier((byte[]) trustedDomain.Properties["objectSid"].Value, 0).ToString();
domainSidMapping.Add(domainSid, trust.TargetName);
} catch (Exception e) {
//This can happen if you're running this with credentials
//that aren't trusted on the other domain or if the domain
//can't be contacted
throw new Exception($"Can't connect to domain {trust.TargetName}: {e.Message}", e);
}
}
}
}
while (true) {
var memberDns = group.Properties["member"];
foreach (string member in memberDns) {
using (var memberDe = new DirectoryEntry($"LDAP://{member.Replace("/", "\/")}")) {
memberDe.RefreshCache(new[] { "objectClass", "msDS-PrincipalName", "cn" });
if (recursive && memberDe.Properties["objectClass"].Contains("group")) {
members.AddRange(GetGroupMemberList(memberDe, true, domainSidMapping));
} else if (memberDe.Properties["objectClass"].Contains("foreignSecurityPrincipal")) {
//User is on a trusted domain
var foreignUserSid = memberDe.Properties["cn"].Value.ToString();
//The SID of the domain is the SID of the user minus the last block of numbers
var foreignDomainSid = foreignUserSid.Substring(0, foreignUserSid.LastIndexOf("-"));
if (domainSidMapping.TryGetValue(foreignDomainSid, out var foreignDomainDns)) {
using (var foreignMember = new DirectoryEntry($"LDAP://{foreignDomainDns}/<SID={foreignUserSid}>")) {
foreignMember.RefreshCache(new[] { "msDS-PrincipalName", "objectClass" });
if (recursive && foreignMember.Properties["objectClass"].Contains("group")) {
members.AddRange(GetGroupMemberList(foreignMember, true, domainSidMapping));
} else {
members.Add(foreignMember.Properties["msDS-PrincipalName"].Value.ToString());
}
}
} else {
//unknown domain
members.Add(foreignUserSid);
}
} else {
var username = memberDe.Properties["msDS-PrincipalName"].Value.ToString();
if (!string.IsNullOrEmpty(username)) {
members.Add(username);
}
}
}
}
if (memberDns.Count == 0) break;
try {
group.RefreshCache(new[] {$"member;range={members.Count}-*"});
} catch (COMException e) {
if (e.ErrorCode == unchecked((int) 0x80072020)) { //no more results
break;
}
throw;
}
}
return members;
}
我有 2 个域 A 和 B。我在 B "GroupInB" 中有一个组,其中有一个用户 "UserInB"(将来,该组中可以有很多用户)。在域A中,我创建了一个组"GroupInA",然后将"GroupInB"添加到"GroupInA"。 (这会导致 GroupB 的 ForeignSecurityPrincipal)。而且我在 "GroupA".
中添加了一个用户 "UserInA"现在的问题是,我想读取"GroupA"中的所有用户。我希望结果是
- UserInA
- UserInB
但是当尝试从 DirectoryEntry 读取用户时,我得到的只是
- UserInA
- GroupInB
有什么方法可以让我也从 "GroupInB" 获得用户吗? :(
前阵子写了一篇关于获取一个组的所有成员的文章:Find all the members of a group
我包括了关于 finding users from external trusted domains 的部分,它显示为外国安全主体,但我似乎忘记了这个特定的用例:来自外部域的组是其中的成员。所以我更新了文章中的代码并将其包含在下面。
这有点复杂,因为外部安全主体具有外部域上对象的 SID,但要使用 SID 绑定到对象,您必须使用域的 DNS 名称。因此,我们首先需要为所有受信任的域创建域 SID 和 DNS 名称的映射。但是,如果您 运行 仅在一个环境中使用此功能,则始终可以对域列表进行硬编码以加快速度。
这是代码。如果你给recursive
参数传递true
,它会展开所有成员组。
public static IEnumerable<string> GetGroupMemberList(DirectoryEntry group, bool recursive = false, Dictionary<string, string> domainSidMapping = null) {
var members = new List<string>();
group.RefreshCache(new[] { "member", "canonicalName" });
if (domainSidMapping == null) {
//Find all the trusted domains and create a dictionary that maps the domain's SID to its DNS name
var groupCn = (string) group.Properties["canonicalName"].Value;
var domainDns = groupCn.Substring(0, groupCn.IndexOf("/", StringComparison.Ordinal));
var domain = Domain.GetDomain(new DirectoryContext(DirectoryContextType.Domain, domainDns));
var trusts = domain.GetAllTrustRelationships();
domainSidMapping = new Dictionary<string, string>();
foreach (TrustRelationshipInformation trust in trusts) {
using (var trustedDomain = new DirectoryEntry($"LDAP://{trust.TargetName}")) {
try {
trustedDomain.RefreshCache(new [] {"objectSid"});
var domainSid = new SecurityIdentifier((byte[]) trustedDomain.Properties["objectSid"].Value, 0).ToString();
domainSidMapping.Add(domainSid, trust.TargetName);
} catch (Exception e) {
//This can happen if you're running this with credentials
//that aren't trusted on the other domain or if the domain
//can't be contacted
throw new Exception($"Can't connect to domain {trust.TargetName}: {e.Message}", e);
}
}
}
}
while (true) {
var memberDns = group.Properties["member"];
foreach (string member in memberDns) {
using (var memberDe = new DirectoryEntry($"LDAP://{member.Replace("/", "\/")}")) {
memberDe.RefreshCache(new[] { "objectClass", "msDS-PrincipalName", "cn" });
if (recursive && memberDe.Properties["objectClass"].Contains("group")) {
members.AddRange(GetGroupMemberList(memberDe, true, domainSidMapping));
} else if (memberDe.Properties["objectClass"].Contains("foreignSecurityPrincipal")) {
//User is on a trusted domain
var foreignUserSid = memberDe.Properties["cn"].Value.ToString();
//The SID of the domain is the SID of the user minus the last block of numbers
var foreignDomainSid = foreignUserSid.Substring(0, foreignUserSid.LastIndexOf("-"));
if (domainSidMapping.TryGetValue(foreignDomainSid, out var foreignDomainDns)) {
using (var foreignMember = new DirectoryEntry($"LDAP://{foreignDomainDns}/<SID={foreignUserSid}>")) {
foreignMember.RefreshCache(new[] { "msDS-PrincipalName", "objectClass" });
if (recursive && foreignMember.Properties["objectClass"].Contains("group")) {
members.AddRange(GetGroupMemberList(foreignMember, true, domainSidMapping));
} else {
members.Add(foreignMember.Properties["msDS-PrincipalName"].Value.ToString());
}
}
} else {
//unknown domain
members.Add(foreignUserSid);
}
} else {
var username = memberDe.Properties["msDS-PrincipalName"].Value.ToString();
if (!string.IsNullOrEmpty(username)) {
members.Add(username);
}
}
}
}
if (memberDns.Count == 0) break;
try {
group.RefreshCache(new[] {$"member;range={members.Count}-*"});
} catch (COMException e) {
if (e.ErrorCode == unchecked((int) 0x80072020)) { //no more results
break;
}
throw;
}
}
return members;
}