Есть ли класс .NET, который может анализировать строки CN = из LDAP?

У меня есть строка, которую я беру из LDAP для членства в группе Active Directory, и мне нужно проанализировать ее, чтобы проверить, является ли пользователь членом группы AD. Есть ли класс, который может разобрать это за меня?

Пример:

CN=Foo Group Name,DC=mydomain,DC=com

person Gabe Brown    schedule 30.09.2010    source источник
comment
Похоже, вам нужно регулярное выражение - RegEx должен работать ...   -  person Jeremy McGee    schedule 30.09.2010
comment
См. stackoverflow.com/questions/ 356480 /   -  person nos    schedule 30.09.2010
comment
Я не хочу использовать RegEx, потому что не хочу нести расходы на тестирование. Спасибо за предложение.   -  person Gabe Brown    schedule 30.09.2010


Ответы (6)


Кроме того, если вы запросите AD для членов группы, вы сможете напрямую сравнить отличительные имена всех членов, не анализируя код через класс DirectoryEntry пространства имен System.DirectoryServices.

В остальном я просто где-то не знаю такого класса. знак равно

Надеюсь, это хоть как-то поможет!

ИЗМЕНИТЬ №1

Вот ссылка, по которой я многому научился, работая с AD и пространством имен System.DirectoryServices: _ 4_

Я предоставлю вам образец кода через несколько дней, если он вам все еще понадобится, где я буду использовать объектный класс System.DirectoryServices.DirectorySearcher для извлечения членов группы.

Надеюсь, эта ссылка поможет вам, как и мне! знак равно

ИЗМЕНИТЬ №2

Вот пример кода, о котором я вам рассказал. Это должно сделать более эффективным запрос к AD без необходимости работать bakc и далее AD.

public IList<string> GetMembers(string groupName) {
    if (string.IsNullOrEmpty(groupName))
        throw new ArgumentNullException("groupName");

    IList<string> members = new List<string>();

    DirectoryEntry root = new DirectoryEntry(@"LDAP://my.domain.com");
    DirectorySearcher searcher = new DirectorySearcher();
    searcher.SearchRoot = root;
    searcher.SearchScope = SearchScope.Subtree;
    searcher.PropertiesToLoad.Add("member");

    searcher.Filter = string.Format("(&(objectClass=group)(sAMAccountName={0}))", groupName);

    SearchResult result = searcher.FindOne();
    DirectoryEntry groupFound = result.GetDirectoryEntry();
    for (int index = 0; index < ((object[])groupFound.Properties["member"].Value).Length; ++index)
        members.Add((string)((object[])groupFound.Properties["member"].Value)[index]);

    return members;

}

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

person Will Marcouiller    schedule 30.09.2010
comment
У меня это сработало очень хорошо, проблема в том, что туда и обратно с AD обходятся довольно дорого. Пытаюсь получить их все сразу. - person Gabe Brown; 01.10.2010
comment
Если вы используете .NET 3.5 или можете использовать пространство имен System.Linq, возможно, вам будет интересно взглянуть на проект LINQ to AD Барта Де Смета на Codeplex. Это позволяет использовать LINQ для запросов к AD. Действительно, нужно немного поработать, чтобы завершить библиотеку, но наиболее важные аспекты покрыты его открытым исходным кодом. - person Will Marcouiller; 01.10.2010
comment
Если вам нужны непосредственные члены группы, вызовите DirectorySearcher против DN группы и получите ее атрибут members для списка DN. Если вам нужны вложенные члены групп внутри группы, получите атрибут tokenGroups для списка SID объектов. Я писал об этом некоторое время назад: explodingcoder.com/ блог / контент / - person spoulson; 01.10.2010
comment
Правильно ! Класс DirectorySearcher используется для запроса к AD. Спасибо за упоминание @spoulson! Совсем забыл про это на немногих! знак равно - person Will Marcouiller; 01.10.2010

Если вы не хотите добавлять дополнительные зависимости и просто хотите проанализировать строку ...

Этот тип строки можно легко проанализировать, просто используя string.Split. Чтобы получить значения CN, это будет что-то вроде ..

string[] split = "CN=Foo Group Name,DC=mydomain,DC=com".Split(',');
List<string> cnValues = new List<string>();
foreach(string pair in split){
    string[] keyValue=pair.Split('=');
    if(keyValue[0]=="CN")
       cnValues.Add(keyValue[1]);
}
person markt    schedule 30.09.2010
comment
Для тех, кто читает назад, этого решения недостаточно для производственной среды - RFC указывает, что значения можно заключать в кавычки, а также существуют правила экранирования символов. Кроме того, разделение строки запятыми в этом формате очень опасно. - person Jon Seigel; 23.03.2011

Их называют выдающимися именами.

CodeProject имеет проект парсера, который, похоже, делает то, что вам нужно: http://www.codeproject.com/KB/IP/dnparser.aspx

person spoulson    schedule 30.09.2010
comment
Он также был заключен в проект github и пакет nuget для облегчения доступа. github.com/picrap/DNParser/blob/master/README.md - person John K; 02.03.2018

Чтобы разобрать DistinquishedName, вы должны обратить внимание на escape-символы. Вот метод, который правильно проанализирует строку и вернет список пар ключ-значение.

    public static List<KeyValuePair<string, string>> ParseDistinguishedName(string input)
    {
        int i = 0;
        int a = 0;
        int v = 0;
        var attribute = new char[50];
        var value = new char[200];
        var inAttribute = true;
        string attributeString, valueString;
        var names = new List<KeyValuePair<string, string>>();

        while (i < input.Length)
        {
            char ch = input[i++];
            switch(ch)
            {
                case '\\':
                    value[v++] = ch;
                    value[v++] = input[i++];
                    break;
                case '=':
                    inAttribute = false;
                    break;
                case ',':
                    inAttribute = true;
                    attributeString = new string(attribute).Substring(0, a);
                    valueString = new string(value).Substring(0, v);
                    names.Add(new KeyValuePair<string, string>(attributeString, valueString));
                    a = v = 0;
                    break;
                default:
                    if (inAttribute)
                    {
                        attribute[a++] = ch;
                    }
                    else
                    {
                        value[v++] = ch;
                    }
                    break;
            }
        }

        attributeString = new string(attribute).Substring(0, a);
        valueString = new string(value).Substring(0, v);
        names.Add(new KeyValuePair<string, string>(attributeString, valueString));
        return names;
    }

    static void Main(string[] args)
    {
        const string TestString = "CN=BY2STRAKRJOB2,OU=MSNStorage,OU=RESOURCE,OU=PRODUCTION,DC=phx,DC=gbl,STREET=street address,L=locality Name,C=Country Name,UID=user id,STUFF=\\,\\.\\+\"<>;\\=\\0A";

        var names = ParseDistinguishedName(TestString);
        foreach (var pair in names)
        {
            Console.WriteLine("{0} = {1}", pair.Key, pair.Value);
        }
    }
person Rockfish    schedule 16.08.2014
comment
Очень похоже на этот подход - хотя он не обрезает пробелы в именах атрибутов, и у меня тоже были некоторые проблемы с цитируемыми значениями, например. O = VeriSign, Inc. - поэтому я немного подправил gist.github.com/davetransom/e9c58b96afa - person Dave Transom; 11.04.2015

Я пришел сюда, чтобы узнать, можем ли мы проанализировать "LDAP: //ldap.company.com: 389 / ou = people, o = company" на протокол, порт, baseDN и полное доменное имя сервера. Я попробовал класс System.Uri, он работал как исключение.

person Vivek Raj    schedule 19.09.2018

Чтобы ответить на вопрос синтаксического анализа, используйте PInvoke с DsGetRdnW. Код см. В моем ответе на другой вопрос: https://stackoverflow.com/a/11091804/628981.

Но похоже, что вы делаете это неправильно. Сначала получите SID для своей целевой группы:

string targetGroupName = //target group name;
DirectorySearcher dsTargetGroup = new DirectorySearcher();
dsTargetGroup.Filter = string.Format("(sAMAccountName={0})", targetGroupName);
SearchResult srTargetGroup = dsTargetGroup.FindOne();
DirectoryEntry deTargetGroup = srTargetGroup.GetDirectoryEntry();
byte[] byteSid = (byte[])deTargetGroup.Properties["objectSid"].Value;
SecurityIdentifier targetGroupSid = new SecurityIdentifier(byteSid, 0);

Тогда это зависит от того, что у вас есть. Если пользователь запускает ваше приложение (или аутентифицирован на вашем веб-сайте / службе), укажите идентификаторы безопасности в токене. Например, в настольных приложениях используйте WindowsIdentity.GetCurrent().Groups. В противном случае вам нужно будет получить DirectoryEntry для пользователя, а затем получить атрибут tokenAttributes, как предложил Споулсон:

DirectoryEntry deTargetUser = //target user;
DirectorySearcher dsTargetUser = new DirectorySearcher(deTargetUser);
dsTargetUser.SearchScope = SearchScope.Base; //tokenGroups is a constructed attribute, so have to ask for it while performing a search
dsTargetUser.Filter = "(objectClass=*)"; //this is closest thing I can find to an always true filter
dsTargetUser.PropertiesToLoad.Add("tokenGroups");
SearchResult srTargetUser = dsTargetUser.FindOne();
foreach(byte[] byteGroupSid in srTargetUser.Properties["tokenGroups"])
{
    SecurityIdentifier groupSid = new SecurityIdentifier(byteGroupSid, 0);
    if(groupSid == targetGroupSid)
    {
        //success
    }
}

На всякий случай, если вам нужно получить DirectoryEntry из SID, вы можете получить строку поиска следующим образом:

public static string GetSIDSearchFilter(SecurityIdentifier sid)
{
    byte[] byteSid = new byte[sid.BinaryLength];
    sid.GetBinaryForm(byteSid, 0);
    return string.Format("(objectSid={0})", BuildFilterOctetString(byteSid));
}

public static string BuildFilterOctetString(byte[] bytes)
{
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < bytes.Length; i++)
    {
        sb.AppendFormat("\\{0}", bytes[i].ToString("X2"));
    }
    return sb.ToString();
}
person Sean Hall    schedule 21.11.2012