Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 33 additions & 18 deletions Kerberos.NET/Entities/Krb/KrbPrincipalName.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,20 +80,20 @@ public partial class KrbPrincipalName
{ "msdtc", HostServiceName }
});

private static readonly ReadOnlyMemory<string> NameTypeSeperator = new[]
private static readonly ReadOnlyMemory<char> NameTypeSeperator = new[]
{
"@", // NT_UNKNOWN = 0,
"@", // NT_PRINCIPAL = 1,
"/", // NT_SRV_INST = 2,
"/", // NT_SRV_HST = 3,
"/", // NT_SRV_XHST = 4,
"@", // NT_UID = 5,
",", // NT_X500_PRINCIPAL = 6,
"@", // NT_SMTP_NAME = 7,
"@", // 8
"@", // 9
"@", // NT_ENTERPRISE = 10,
"/" // NT_WELLKNOWN = 11
'@', // NT_UNKNOWN = 0,
'@', // NT_PRINCIPAL = 1,
'/', // NT_SRV_INST = 2,
'/', // NT_SRV_HST = 3,
'/', // NT_SRV_XHST = 4,
'@', // NT_UID = 5,
',', // NT_X500_PRINCIPAL = 6,
'@', // NT_SMTP_NAME = 7,
'@', // 8
'@', // 9
'@', // NT_ENTERPRISE = 10,
'/' // NT_WELLKNOWN = 11
};

internal PrincipalName ToKeyPrincipal()
Expand Down Expand Up @@ -125,9 +125,24 @@ public void Canonicalize(string qualifyShortname)
this.Name[1] = $"{this.Name[1]}.{qualifyShortname}";
}

private static char GetSeperator(PrincipalNameType type)
{
var index = (int)type;

if (index < 0 || index >= NameTypeSeperator.Length)
{
// Name types outside the standard range (e.g. the Microsoft-specific
// KRB5_NT_MS_PRINCIPAL = -128 returned by Windows KDCs during S4U2Self)
// are treated like NT_PRINCIPAL and joined with '@'.
return '@';
}

return NameTypeSeperator.Span[index];
}

private static string MakeFullName(IEnumerable<string> names, PrincipalNameType type, bool normalizeAlias = false)
{
var seperator = NameTypeSeperator.Span[(int)type];
var seperator = GetSeperator(type);

using (var enumerator = names.GetEnumerator())
{
Expand All @@ -140,7 +155,7 @@ private static string MakeFullName(IEnumerable<string> names, PrincipalNameType

string firstPortion = enumerator.Current;

if (seperator == "/" && normalizeAlias)
if (seperator == '/' && normalizeAlias)
{
if (ServiceAliases.TryGetValue(firstPortion.ToLowerInvariant(), out string alias))
{
Expand All @@ -161,9 +176,9 @@ private static string MakeFullName(IEnumerable<string> names, PrincipalNameType
{
if (enumerator.Current != null)
{
if (seperator != ",")
if (seperator != ',')
{
sb.Append("@");
sb.Append('@');
}
else
{
Expand Down Expand Up @@ -242,7 +257,7 @@ public static KrbPrincipalName FromString(

var actualType = type ?? TryDetectType(principal);

var splitOn = NameTypeSeperator.Span[(int)actualType][0];
var splitOn = GetSeperator(actualType);

if (splitOn == '@')
{
Expand Down
18 changes: 18 additions & 0 deletions Kerberos.NET/Entities/PrincipalNameType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,24 @@ namespace Kerberos.NET.Entities
/// </summary>
public enum PrincipalNameType
{
/// <summary>
/// A Microsoft-specific principal name (KRB5_NT_MS_PRINCIPAL). Windows KDCs may return this
/// name type (for example in an S4U2Self reply). It is treated like <see cref="NT_PRINCIPAL" />.
/// </summary>
NT_MS_PRINCIPAL = -128,

/// <summary>
/// A Microsoft-specific principal name with a SID (KRB5_NT_MS_PRINCIPAL_AND_ID).
/// It is treated like <see cref="NT_PRINCIPAL" />.
/// </summary>
NT_MS_PRINCIPAL_AND_ID = -129,

/// <summary>
/// A Microsoft-specific enterprise principal name with a SID (KRB5_NT_ENT_PRINCIPAL_AND_ID).
/// It is treated like <see cref="NT_PRINCIPAL" />.
/// </summary>
NT_ENT_PRINCIPAL_AND_ID = -130,

/// <summary>
/// The principal name format is unknown and will be treated like <see cref="NT_PRINCIPAL" />
/// </summary>
Expand Down
31 changes: 26 additions & 5 deletions Tests/Tests.Kerberos.NET/KrbApReq/PrincipalNameTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,14 +147,35 @@ public void PrincipalName_Equality_DifferentServiceTypes()
}

[TestMethod]
public void PrincipalName_Equality_ServiceTypeAliasesMatch()
public void PrincipalName_MsPrincipal_DoesNotThrow()
{
var a = KrbPrincipalName.FromString("host/aaaa");
var b = KrbPrincipalName.FromString("bbbb/aaaa");
var principal = new KrbPrincipalName
{
Type = PrincipalNameType.NT_MS_PRINCIPAL,
Name = new[] { "testuser" }
};

KrbPrincipalName.ServiceAliases["bbbb"] = "host";
Assert.AreEqual("testuser", principal.FullyQualifiedName);
}

Assert.IsTrue(a.Matches(b));
[TestMethod]
public void PrincipalName_MsPrincipal_WithUpn()
{
var principal = new KrbPrincipalName
{
Type = PrincipalNameType.NT_MS_PRINCIPAL,
Name = new[] { "testuser@domain.local" }
};

Assert.AreEqual("testuser@domain.local", principal.FullyQualifiedName);
}

[TestMethod]
public void PrincipalName_MsPrincipal_FromString()
{
var principal = KrbPrincipalName.FromString("testuser@domain.local", PrincipalNameType.NT_MS_PRINCIPAL);

Assert.AreEqual("testuser@domain.local", principal.FullyQualifiedName);
}
}
}
Loading