Как получить подробную информацию об объекте ForeignSecurityPrincipal в .net

У меня есть 2 домена A и B. У меня есть группа в B «GroupInB», в которой есть пользователь «UserInB» (в будущем в этой группе может быть много пользователей). В домене A я создал группу «GroupInA», а затем добавил «GroupInB» в «GroupInA». (Это вызывает ForeignSecurityPrincipal для GroupB). А также я добавил пользователя «UserInA» в «GroupA».

Теперь проблема в том, что я хочу прочитать всех пользователей в «Группе А». Я ожидаю, что результат будет

  1. UserInA
  2. UserInB

Но при попытке прочитать пользователей из DirectoryEntry все, что я получаю, это

  1. UserInA
  2. GroupInB

Есть ли способ получить пользователей из "GroupInB"? :(


person Shrikey    schedule 23.01.2019    source источник
comment
Пожалуйста, проверьте эту ссылку: stackoverflow.com/questions/3665487/!   -  person Am_I_Helpful    schedule 24.01.2019
comment
@Am_I_Helpful: ссылка, которую вы указали, помогает в поиске групп в том же домене. В моем случае GroupB добавлена ​​из другого домена. Я могу прочитать имя группы B, но не пользователей в ней.   -  person Shrikey    schedule 24.01.2019
comment
В этом случае делегируйте соответствующее разрешение пользователю, который также может читать групповое членство пользователей в другом домене, а затем следуйте коду, выделенному в моей ссылке выше.   -  person Am_I_Helpful    schedule 24.01.2019
comment
@Am_I_Helpful: я не уверен, как назначить разрешение, но проблема в этом случае заключается в том, что GroupB не будет группой или пользователем. Это будет ForeignSecurityPrincipal. И не могу извлечь из него членов.. Уже пробовал аналогичный подход, но безуспешно :(   -  person Shrikey    schedule 24.01.2019


Ответы (1)


Недавно я написал статью о получении всех членов группы: Найти всех участников группы

Я включил часть о поиск пользователей из внешних доверенных доменов, которые отображаются как внешние участники безопасности, однако, кажется, я забыл об этом конкретном случае использования: где членом является группа из внешнего домена. Поэтому я обновил код в своей статье и включил его ниже.

Это немного сложно, поскольку субъект внешней безопасности имеет SID объекта во внешнем домене, но для привязки к объекту с использованием SID необходимо использовать DNS-имя домена. Итак, сначала нам нужно создать сопоставление доменных SID и DNS-имен для всех доверенных доменов. Однако, если вы используете это только в одной среде, вы всегда можете жестко закодировать список доменов, чтобы ускорить это.

Это код. Если вы передадите true для параметра recursive, он расширит все группы участников.

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;
}
person Gabriel Luci    schedule 24.01.2019
comment
Ты послан Богом, мой друг .. Работал как шарм :) - person Shrikey; 25.01.2019