Подтвердить что ты не робот

Извлечь общее имя из отличительного имени

Есть ли вызов в .NET, который анализирует CN из кодированного rfc-2253 различного имени? Я знаю, что есть некоторые сторонние библиотеки, которые это делают, но я предпочел бы использовать собственные библиотеки .NET, если это возможно.

Примеры строкового кодирования DN

CN = L. Eagle, O = Sue \, Grabbit и Runn, C = GB

CN = Jeff Smith, OU = Sales, DC = Fabrikam, DC = COM

4b9b3361

Ответ 1

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

string dn = "CN=TestGroup,OU=Groups,OU=UT-SLC,OU=US,DC=Company,DC=com";
Assembly dirsvc = Assembly.Load("System.DirectoryServices");
Type asmType = dirsvc.GetType("System.DirectoryServices.ActiveDirectory.Utils");
MethodInfo mi = asmType.GetMethod("GetDNComponents", BindingFlags.NonPublic | BindingFlags.Static);
string[] parameters = { dn };
var test = mi.Invoke(null, parameters);
//test.Dump("test1");//shows details when using Linqpad 

//Convert Distinguished Name (DN) to Relative Distinguished Names (RDN) 
MethodInfo mi2 = asmType.GetMethod("GetRdnFromDN", BindingFlags.NonPublic | BindingFlags.Static);
var test2 = mi2.Invoke(null, parameters);
//test2.Dump("test2");//shows details when using Linqpad 

Результаты будут выглядеть так:

//test1 is array of internal "Component" struct that has name/values as strings
Name   Value 
CN     TestGroup 
OU     Groups 
OU     UT-SLC
OU     US 
DC     company 
DC     com 


//test2 is a string with CN=RDN 
CN=TestGroup 

Пожалуйста, не считайте, что это внутренний служебный класс, который может измениться в будущем выпуске.

Ответ 2

Если вы работаете с X509Certificate2, есть собственный метод, который вы можете использовать для извлечения простого имени. Простое имя эквивалентно RDN Common Name в поле Subject основного сертификата:

x5092Cert.GetNameInfo(X509NameType.SimpleName, false);

В качестве альтернативы, X509NameType.DnsName можно использовать для получения альтернативного имени субъекта, если оно имеется; в противном случае по умолчанию будет использоваться общее имя:

x5092Cert.GetNameInfo(X509NameType.DnsName, false);

Ответ 3

У меня был тот же самый вопрос, когда я нашел твое. Не нашел ничего в BCL; однако я наткнулся на эту статью CodeProject, которая сразу же ударила ноготь по голове.

Я надеюсь, что это тоже поможет вам.

http://www.codeproject.com/Articles/9788/An-RFC-2253-Compliant-Distinguished-Name-Parser

Ответ 4

Учитываются ли функции Win32? Вы можете использовать PInvoke с DsGetRdnW. Для кода см. Мой ответ на другой вопрос: fooobar.com/questions/282894/....

Ответ 5

Просто добавьте мои два цента здесь. Эта реализация работает "лучше", если вы сначала узнаете, какие бизнес-правила существуют, что в конечном итоге будет определять, какая часть RFC будет реализована в вашей компании.

private static string ExtractCN(string distinguishedName)
{
    // CN=...,OU=...,OU=...,DC=...,DC=...
    string[] parts;

    parts = distinguishedName.Split(new[] { ",DC=" }, StringSplitOptions.None);
    var dc = parts.Skip(1);

    parts = parts[0].Split(new[] { ",OU=" }, StringSplitOptions.None);
    var ou = parts.Skip(1);

    parts = parts[0].Split(new[] { ",CN=" }, StringSplitOptions.None);
    var cnMulti = parts.Skip(1);

    var cn = parts[0];

    if (!Regex.IsMatch(cn, "^CN="))
        throw new CustomException(string.Format("Unable to parse distinguishedName for commonName ({0})", distinguishedName));

    return Regex.Replace(cn, "^CN=", string.Empty);
}

Ответ 6

Если порядок не определен, я делаю это:

private static string ExtractCN(string dn)
{
    string[] parts = dn.Split(new char[] { ',' });

    for (int i = 0; i < parts.Length; i++)
    {
        var p = parts[i];
        var elems = p.Split(new char[] { '=' });
        var t = elems[0].Trim().ToUpper();
        var v = elems[1].Trim();
        if (t == "CN")
        {
            return v;
        }
    }
    return null;
}

Ответ 7

Не могли бы вы просто получить значения атрибута CN?

Как вы правильно заметили, используйте чужой класс, так как есть много забавных фреймов (экранированные запятые, экранированные другие символы), которые делают разбор DN красивым, но на самом деле достаточно сложным.

Обычно я использую класс Java, который поставляется с Novell (Now NetID) Identity Manager. Так что это не полезно.

Ответ 9

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

(?:^|,\s?)(?:(?<name>[AZ]+)=(?<val>"(?:[^"]|"")+"|(?:\\,|[^,])+))+

Здесь это отформатировано немного лучше, и с некоторыми комментариями:

(?:^|,\s?)               <-- Start or a comma
(?:
    (?<name>[A-Z]+)
    =
    (?<val>
        "(?:[^"]|"")+"   <-- Quoted strings
        |
        (?:\\,|[^,])+    <-- Unquoted strings
    )
)+

Это регулярное выражение даст вам name и группы захвата val для каждого матча.

Строки DN могут быть заключены в кавычки (например, "Hello", что позволяет им содержать неэкранированные запятые. В качестве альтернативы, если не заключено в кавычки, запятые должны быть экранированы с обратной косой чертой (например, Hello\, there!). Это регулярное выражение обрабатывает строки как в кавычках, так и в кавычках,

Вот ссылка, чтобы вы могли увидеть ее в действии: https://regex101.com/r/7vhdDz/1

Ответ 10

Это мой почти RFC-совместимый отказоустойчивый анализатор DN, полученный из https://www.codeproject.com/Articles/9788/An-RFC-2253-Compliant-Distinguished-Name-Parser и пример его использования (извлечь тему имена как CN и O, необязательные, соединенные запятой):

    private static string GetCertificateString(X509Certificate2 certificate)
    {
        var subjectComponents = certificate.Subject.ParseDistinguishedName();
        var subjectName = string.Join(", ", subjectComponents
            .Where(m => (m.Item1 == "CN") || (m.Item1 == "O"))
            .Select(n => n.Item2)
            .Distinct());

        return $"{certificate.SerialNumber} {certificate.NotBefore:yyyy.MM.dd}-{certificate.NotAfter:yyyy.MM.dd} {subjectName}";
    }

    private enum DistinguishedNameParserState
    {
        Component,
        QuotedString,
        EscapedCharacter,
    };

    public static IEnumerable<Tuple<string, string>> ParseDistinguishedName(this string value)
    {
        var previousState = DistinguishedNameParserState.Component;
        var currentState = DistinguishedNameParserState.Component;
        var currentComponent = new StringBuilder();
        var previousChar = char.MinValue;
        var position = 0;

        Func<StringBuilder, Tuple<string, string>> parseComponent = sb =>
        {
            var s = sb.ToString();
            sb.Clear();

            var index = s.IndexOf('=');
            if (index == -1)
            {
                return null;
            }

            var item1 = s.Substring(0, index).Trim().ToUpper();
            var item2 = s.Substring(index + 1).Trim();

            return Tuple.Create(item1, item2);
        };

        while (position < value.Length)
        {
            var currentChar = value[position];

            switch (currentState)
            {
                case DistinguishedNameParserState.Component:
                    switch (currentChar)
                    {
                        case ',':
                        case ';':
                            // Separator found, yield parsed component
                            var component = parseComponent(currentComponent);
                            if (component != null)
                            {
                                yield return component;
                            }
                            break;

                        case '\\':
                            // Escape character found
                            previousState = currentState;
                            currentState = DistinguishedNameParserState.EscapedCharacter;
                            break;

                        case '"':
                            // Quotation mark found
                            if (previousChar == currentChar)
                            {
                                // Double quotes inside quoted string produce single quote
                                currentComponent.Append(currentChar);
                            }
                            currentState = DistinguishedNameParserState.QuotedString;
                            break;

                        default:
                            currentComponent.Append(currentChar);
                            break;
                    }
                    break;

                case DistinguishedNameParserState.QuotedString:
                    switch (currentChar)
                    {
                        case '\\':
                            // Escape character found
                            previousState = currentState;
                            currentState = DistinguishedNameParserState.EscapedCharacter;
                            break;

                        case '"':
                            // Quotation mark found
                            currentState = DistinguishedNameParserState.Component;
                            break;

                        default:
                            currentComponent.Append(currentChar);
                            break;
                    }
                    break;

                case DistinguishedNameParserState.EscapedCharacter:
                    currentComponent.Append(currentChar);
                    currentState = previousState;
                    currentChar = char.MinValue;
                    break;
            }

            previousChar = currentChar;
            position++;
        }

        // Yield last parsed component, if any
        if (currentComponent.Length > 0)
        {
            var component = parseComponent(currentComponent);
            if (component != null)
            {
                yield return component;
            }
        }
    }

Ответ 11

char [] character = {','}; string alteredName = item.Properties ["manager"] [0].ToString(). Replace ("CN =", "").Replace("\", ""); string [] manager = alteredName.Split (символ);

obj.Manager = manager [0] + "," + manager [1];

Ответ 12

using System.Linq; 

var dn = "CN=Jeff Smith,OU=Sales,DC=Fabrikam,DC=COM";
var cn = dn.Split(',').Where(i => i.Contains("CN=")).Select(i => i.Replace("CN=", "")).FirstOrDefault();