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

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

Пример:

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

Ответ 1

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

В противном случае я просто не знаю такого класса. =)

Надеюсь, это так или иначе поможет!

РЕДАКТИРОВАТЬ № 1

Здесь ссылка, с которой я многому научился работать с AD и пространством имен System.DirectoryServices: Howto: (Almost) Everything In Active Directory via C#

Я дам вам пример кода через несколько дней, если вы все еще требуете его, где я буду использовать класс объекта 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;

}

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

Ответ 2

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

Этот тип строки легко анализируется с помощью 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]);
}

Ответ 3

Они называются отличительными именами.

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

Ответ 4

Чтобы разобрать 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);
        }
    }

Ответ 5

Using System.DirectoryServices;

namespace GetGroups
{
    public string GetGroupName(string LDAPGroupEntry)
    {
        // LDAPGroupEntry is in the form "LDAP://CN=Foo Group Name,DC=mydomain,DC=com"
        DirectoryEntry grp = new DirectoryEntry(LDAPGroupEntry);
        return grp.Properties["Name"].Value.ToString();
    }
}

Ответ 6

Чтобы ответить на вопрос о синтаксическом анализе, используйте PInvoke с DsGetRdnW. Для кода см. Мой ответ на другой вопрос: fooobar.com/info/282894/....

Но похоже, что вы делаете это неправильно. Во-первых, получите 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);

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

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();
}