从专有名称中提取通用名称

发布于 2024-12-08 11:01:16 字数 231 浏览 0 评论 0原文

.NET 中是否存在从 rfc-2253 编码的专有名称解析 CN 的调用?我知道有一些第三方库可以执行此操作,但如果可能的话,我更愿意使用本机 .NET 库。

字符串编码的 DN 示例

CN=L。 Eagle,O=Sue\,Grabbit 和 Runn,C=GB

CN=杰夫·史密斯,OU=销售,DC=Fabrikam,DC=COM

Is there a call in .NET that parses the CN from a rfc-2253 encoded distinguished name? I know there are some third-party libraries that do this, but I would prefer to use native .NET libraries if possible.

Examples of a string encoded DN

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

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

许你一世情深 2024-12-15 11:01:16

如果您使用的是 X509Certificate2,可以使用一种方法来提取简单名称。简单名称相当于主证书的主题字段中的通用名称 RDN:

x5092Cert.GetNameInfo(X509NameType.SimpleName, false);

或者,可以使用 X509NameType.DnsName 检索主题备用名称(如果存在);否则,它将默认为通用名称:

x5092Cert.GetNameInfo(X509NameType.DnsName, false);

If you are working with an X509Certificate2, there is a method that you can use to extract the Simple Name. The Simple Name is equivalent to the Common Name RDN within the Subject field of the main certificate:

x5092Cert.GetNameInfo(X509NameType.SimpleName, false);

Alternatively, X509NameType.DnsName can be used to retrieve the Subject Alternative Name, if present; otherwise, it will default to the Common Name:

x5092Cert.GetNameInfo(X509NameType.DnsName, false);
在梵高的星空下 2024-12-15 11:01:16

在深入研究 .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 

请注意,这是一个内部实用程序类,可能会在将来的版本中更改。

After digging around in the .NET source code it looks like there is an internal utility class that can parse Distinguished Names into their different components. Unfortunately the utility class is not made public, but you can access it using reflection:

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 

The results would look like this:

//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 

Please not this is an internal utility class and could change in a future release.

枯叶蝶 2024-12-15 11:01:16

当我找到你的问题时,我自己也有同样的问题。在 BCL 中没有找到任何内容;然而,我确实偶然发现了这篇 CodeProject 文章,它一语中的。

我希望它也能帮助你。

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

I had the same question, myself, when I found yours. Didn't find anything in the BCL; however, I did stumble across this CodeProject article that hit the nail squarely on the head.

I hope it helps you out, too.

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

嗳卜坏 2024-12-15 11:01:16

如果您使用的是 Windows,@MaxKiselev 的答案 效果很好。在非 Windows 平台上,它返回每个属性的 ASN1 转储。

.Net Core 5+ 包含 ASN1 解析器,因此您可以使用 AsnReader 以跨平台方式访问 RDN。

Helper 类:

public static class X509DistinguishedNameExtensions
{ 
    public static IEnumerable<KeyValuePair<string, string>> GetRelativeNames(this X500DistinguishedName dn)
    {
        var reader = new AsnReader(dn.RawData, AsnEncodingRules.BER);
        var snSeq = reader.ReadSequence();
        if (!snSeq.HasData)
        {
            throw new InvalidOperationException();
        }

        // Many types are allowable.  We're only going to support the string-like ones
        // (This excludes IPAddress, X400 address, and other wierd stuff)
        // https://www.rfc-editor.org/rfc/rfc5280#page-37
        // https://www.rfc-editor.org/rfc/rfc5280#page-112
        var allowedRdnTags = new[]
        {
            UniversalTagNumber.TeletexString, UniversalTagNumber.PrintableString,
            UniversalTagNumber.UniversalString, UniversalTagNumber.UTF8String,
            UniversalTagNumber.BMPString, UniversalTagNumber.IA5String,
            UniversalTagNumber.NumericString, UniversalTagNumber.VisibleString,
            UniversalTagNumber.T61String
        };
        while (snSeq.HasData)
        {
            var rdnSeq = snSeq.ReadSetOf().ReadSequence();
            var attrOid = rdnSeq.ReadObjectIdentifier();
            var attrValueTagNo = (UniversalTagNumber)rdnSeq.PeekTag().TagValue;
            if (!allowedRdnTags.Contains(attrValueTagNo))
            {
                throw new NotSupportedException($"Unknown tag type {attrValueTagNo} for attr {attrOid}");
            }
            var attrValue = rdnSeq.ReadCharacterString(attrValueTagNo);
            var friendlyName = new Oid(attrOid).FriendlyName;
            yield return new KeyValuePair<string, string>(friendlyName ?? attrOid, attrValue);
        }
    }
}

用法示例:

// Subject: CN=Example, O=Organization
var cert = new X509Certificate2("foo.cer");
var names = this.cert.SubjectName.GetRelativeNames().ToArray();
// names has [ { "CN": "Example" }, { "O": "Organization" } ]

由于这不涉及任何字符串解析,因此不会错误处理转义或注入。它不支持解码包含非字符串元素的 DN,但这些似乎非常罕见。

If you are on Windows, @MaxKiselev's answer works perfectly. On non-Windows platforms, it returns the ASN1 dumps of each attribute.

.Net Core 5+ includes an ASN1 parser, so you can access the RDN's in a cross-platform manner by using AsnReader.

Helper class:

public static class X509DistinguishedNameExtensions
{ 
    public static IEnumerable<KeyValuePair<string, string>> GetRelativeNames(this X500DistinguishedName dn)
    {
        var reader = new AsnReader(dn.RawData, AsnEncodingRules.BER);
        var snSeq = reader.ReadSequence();
        if (!snSeq.HasData)
        {
            throw new InvalidOperationException();
        }

        // Many types are allowable.  We're only going to support the string-like ones
        // (This excludes IPAddress, X400 address, and other wierd stuff)
        // https://www.rfc-editor.org/rfc/rfc5280#page-37
        // https://www.rfc-editor.org/rfc/rfc5280#page-112
        var allowedRdnTags = new[]
        {
            UniversalTagNumber.TeletexString, UniversalTagNumber.PrintableString,
            UniversalTagNumber.UniversalString, UniversalTagNumber.UTF8String,
            UniversalTagNumber.BMPString, UniversalTagNumber.IA5String,
            UniversalTagNumber.NumericString, UniversalTagNumber.VisibleString,
            UniversalTagNumber.T61String
        };
        while (snSeq.HasData)
        {
            var rdnSeq = snSeq.ReadSetOf().ReadSequence();
            var attrOid = rdnSeq.ReadObjectIdentifier();
            var attrValueTagNo = (UniversalTagNumber)rdnSeq.PeekTag().TagValue;
            if (!allowedRdnTags.Contains(attrValueTagNo))
            {
                throw new NotSupportedException(
quot;Unknown tag type {attrValueTagNo} for attr {attrOid}");
            }
            var attrValue = rdnSeq.ReadCharacterString(attrValueTagNo);
            var friendlyName = new Oid(attrOid).FriendlyName;
            yield return new KeyValuePair<string, string>(friendlyName ?? attrOid, attrValue);
        }
    }
}

Example usage:

// Subject: CN=Example, O=Organization
var cert = new X509Certificate2("foo.cer");
var names = this.cert.SubjectName.GetRelativeNames().ToArray();
// names has [ { "CN": "Example" }, { "O": "Organization" } ]

Since this does not involve any string parsing, no escape or injections can be mishandled. It doesn't support decoding DN's that contain non-string elements, but those seem exceedingly rare.

冬天旳寂寞 2024-12-15 11:01:16

您可以使用 AsnEncodedData 类从 ASN.1 编码的专有名称中提取通用名称:

var distinguishedName= new X500DistinguishedName("CN=TestGroup,OU=Groups,OU=UT-SLC,OU=US,DC=Company,DC=com");
var commonNameData = new AsnEncodedData("CN", distinguishedName.RawData);
var commonName = commonNameData.Format(false);

此方法的缺点是,如果您指定无法识别的 OID 或专有名称中缺少用 OID 标识的字段,Format 方法将返回一个十六进制字符串,其中包含完整可分辨名称的编码值,因此您可能需要验证结果。

此外,文档似乎没有指定 AsnEncodedData 构造函数的 rawData 参数是否允许包含除指定为第一个参数之外的其他 OID,因此它可能会在非 Windows 操作系统或未来版本的 .NET Framework 中中断。

You can extract the common name from an ASN.1-encoded distinguished name using AsnEncodedData class:

var distinguishedName= new X500DistinguishedName("CN=TestGroup,OU=Groups,OU=UT-SLC,OU=US,DC=Company,DC=com");
var commonNameData = new AsnEncodedData("CN", distinguishedName.RawData);
var commonName = commonNameData.Format(false);

A downside of this approach is that if you specify an unrecognized OID or the field identified with the OID is missing in the distinguished name, Format method will return a hex string with the encoded value of full distinguished name so you may want to verify the result.

Also the documentation does not seem to specify if the rawData parameter of the AsnEncodedData constructor is allowed to contain other OIDs besides the one specified as the first argument so it may break on non-Windows OS or in a future version of .NET Framework.

站稳脚跟 2024-12-15 11:01:16

Win32 函数算吗?您可以将 PInvoke 与 DsGetRdnW。有关代码,请参阅我对另一个问题的回答:https://stackoverflow.com/a/11091804/628981

Do Win32 functions count? You can use PInvoke with DsGetRdnW. For code, see my answer to another question: https://stackoverflow.com/a/11091804/628981.

世态炎凉 2024-12-15 11:01:16

只是在这里添加我的两分钱。如果您首先了解哪些业务规则将最终决定您公司将实施多少 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);
}

Just adding my two cents here. This implementation works "best" if you first learn what business rules are in place that will ultimately dictate how much of the RFC will ever be implemented at your company.

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);
}
阳光下慵懒的猫 2024-12-15 11:01:16

这个怎么样:

string cnPattern = @"^CN=(?<cn>.+?)(?<!\\),";
string dn        = @"CN=Doe\, John,OU=My OU,DC=domain,DC=com";

Regex re = new Regex(cnPattern);          
Match m  = re.Match(dn);

if (m.Success)
{
  // Item with index 1 returns the first group match.
  string cn = m.Groups[1].Value;
}

改编自 用于提取活动部分的 Powershell 正则表达式目录专有名称

How about this one:

string cnPattern = @"^CN=(?<cn>.+?)(?<!\\),";
string dn        = @"CN=Doe\, John,OU=My OU,DC=domain,DC=com";

Regex re = new Regex(cnPattern);          
Match m  = re.Match(dn);

if (m.Success)
{
  // Item with index 1 returns the first group match.
  string cn = m.Groups[1].Value;
}

Adapted from Powershell Regular Expression for Extracting Parts of an Active Directory Distiniguished Name.

源来凯始玺欢你 2024-12-15 11:01:16

您可以使用正则表达式来执行此操作。这是一个可以解析整个 DN 的正则表达式模式,然后您可以只获取您感兴趣的部分:

(?:^|,\s?)(?:(?[AZ]+) =(?"(?:[^"]|"")+"|(?:\\,|[^,])+))+

这里它的格式更好一点,并附上一些评论:

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

这regex 将为您提供每个匹配的 nameval 捕获组,

可以选择引用 DN 字符串(例如 "Hello",这允许它们包含未转义的逗号。或者,如果未加引号,则必须使用反斜杠转义逗号(例如 Hello\,there!)。

这里有一个链接,以便您可以查看它 。行动中: https://regex101.com/r/7vhdDz/1

You could use regular expressions to do this. Here's a regex pattern than can parse the whole DN, then you can just take the parts you are interested in:

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

Here it is formatted a bit nicer, and with some comments:

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

This regex will give you name and val capture groups for each match.

DN strings can optionally be quoted (e.g. "Hello", which allows them to contain unescaped commas. Alternatively, if not quoted, commas must be escaped with a backslash (e.g. Hello\, there!). This regex handles both quoted and unquoted strings.

Here's a link so you can see it in action: https://regex101.com/r/7vhdDz/1

﹎☆浅夏丿初晴 2024-12-15 11:01:16

如果顺序不确定,我会这样做:

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

If the order is uncertain, I do this:

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;
}
裂开嘴轻声笑有多痛 2024-12-15 11:01:16

这是我的几乎符合 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;
            }
        }
    }

This is my almost RFC-compliant fail-safe DN parser derived from https://www.codeproject.com/Articles/9788/An-RFC-2253-Compliant-Distinguished-Name-Parser and an example of its usage (extract subject name as CN and O, both optional, concatenated with comma):

    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;
            }
        }
    }
臻嫒无言 2024-12-15 11:01:16

抱歉来晚了一点,但我能够直接从 c# 调用 Name 属性

UserPrincipal p 

,然后我能够调用

p.Name 

,这给了我全名(通用名)

示例代码:

string name;
foreach(UserPrincipal p in PSR)
{
     //PSR refers to PrincipalSearchResult
     name = p.Name;
     Console.WriteLine(name); 
 }

显然,您必须填写在空白处。但这应该比解析正则表达式更容易。

Sorry for being a bit late to the party, but I was able to call the Name attribute directly from c#

UserPrincipal p 

and then I was able to call

p.Name 

and that gave me the full name (Common Name)

Sample code:

string name;
foreach(UserPrincipal p in PSR)
{
     //PSR refers to PrincipalSearchResult
     name = p.Name;
     Console.WriteLine(name); 
 }

Obviously, you will have to fill in the blanks. But this should be easier than parsing regex.

南巷近海 2024-12-15 11:01:16

您不能只检索 CN 属性值吗?

正如您正确地注意到的那样,请使用其他人的类,因为有很多有趣的边缘情况(转义逗号、转义其他字符)使得解析 DN 看起来很容易,但实际上相当棘手。

我通常使用 Novell(现在的 NetID)身份管理器附带的 Java 类。所以这没有帮助。

Could you not just retrieve the CN attribute values?

As you correctly note, use someone else's class as there are lots of fun edge cases (escaped commas, escaped other characters) that make parsing a DN look easy, but actually reasonably tricky.

I usually use a Java class that comes with the Novell (Now NetID) Identity Manager. So that is not helpful.

孤凫 2024-12-15 11:01:16
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();
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();
萌面超妹 2024-12-15 11:01:16

好吧,我又是一个迟到的人。这是我的解决方案:

var dn = new X500DistinguishedName("CN=TestGroup,OU=Groups,OU=UT-SLC,OU=US,DC=\"Company, inc\",DC=com");
foreach(var part in dn.Format(true).Split("\r\n"))
{
    if(part == "") continue;
    var parts = part.Split('=', 2);
    var key = parts[0];
    var value = parts[1];
    // use your key and value as you see fit here.
}

基本上它利用 X500DistinguishedName.Format 方法将内容放在线上。然后按行拆分,然后将每一行拆分为键值。

Well, Here I am another person late to the party. Here is my Solution:

var dn = new X500DistinguishedName("CN=TestGroup,OU=Groups,OU=UT-SLC,OU=US,DC=\"Company, inc\",DC=com");
foreach(var part in dn.Format(true).Split("\r\n"))
{
    if(part == "") continue;
    var parts = part.Split('=', 2);
    var key = parts[0];
    var value = parts[1];
    // use your key and value as you see fit here.
}

Basically its leveraging the X500DistinguishedName.Format method to put things on lines. Then split by lines, then split each line into key value.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文