diff --git a/src/libraries/System.Security.Claims/ref/System.Security.Claims.cs b/src/libraries/System.Security.Claims/ref/System.Security.Claims.cs index 4bc8d68fd834a5..2d3b6bd25df300 100644 --- a/src/libraries/System.Security.Claims/ref/System.Security.Claims.cs +++ b/src/libraries/System.Security.Claims/ref/System.Security.Claims.cs @@ -41,11 +41,11 @@ public ClaimsIdentity(System.Collections.Generic.IEnumerable? claims, string? authenticationType) { } public ClaimsIdentity(System.Collections.Generic.IEnumerable? claims, string? authenticationType, string? nameType, string? roleType) { } public ClaimsIdentity(System.IO.BinaryReader reader) { } - [System.ObsoleteAttribute("This API supports obsolete formatter-based serialization. It should not be called or extended by application code.", DiagnosticId = "SYSLIB0051", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + [System.ObsoleteAttribute("This API supports obsolete formatter-based serialization. It should not be called or extended by application code.", DiagnosticId="SYSLIB0051", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] protected ClaimsIdentity(System.Runtime.Serialization.SerializationInfo info) { } - [System.ObsoleteAttribute("This API supports obsolete formatter-based serialization. It should not be called or extended by application code.", DiagnosticId = "SYSLIB0051", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + [System.ObsoleteAttribute("This API supports obsolete formatter-based serialization. It should not be called or extended by application code.", DiagnosticId="SYSLIB0051", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] protected ClaimsIdentity(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } protected ClaimsIdentity(System.Security.Claims.ClaimsIdentity other) { } public ClaimsIdentity(System.Security.Principal.IIdentity? identity) { } @@ -84,8 +84,8 @@ public partial class ClaimsPrincipal : System.Security.Principal.IPrincipal public ClaimsPrincipal() { } public ClaimsPrincipal(System.Collections.Generic.IEnumerable identities) { } public ClaimsPrincipal(System.IO.BinaryReader reader) { } - [System.ObsoleteAttribute("This API supports obsolete formatter-based serialization. It should not be called or extended by application code.", DiagnosticId = "SYSLIB0051", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")] [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)] + [System.ObsoleteAttribute("This API supports obsolete formatter-based serialization. It should not be called or extended by application code.", DiagnosticId="SYSLIB0051", UrlFormat="https://aka.ms/dotnet-warnings/{0}")] protected ClaimsPrincipal(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { } public ClaimsPrincipal(System.Security.Principal.IIdentity identity) { } public ClaimsPrincipal(System.Security.Principal.IPrincipal principal) { } diff --git a/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsIdentity.cs b/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsIdentity.cs index 9733ca86ff10b9..c928dd88501eba 100644 --- a/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsIdentity.cs +++ b/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsIdentity.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.IO; using System.Runtime.Serialization; using System.Security.Principal; @@ -12,6 +13,8 @@ namespace System.Security.Claims /// /// An Identity that is represented by a set of claims. /// + [DebuggerDisplay("{DebuggerToString(),nq}")] + [DebuggerTypeProxy(typeof(ClaimsIdentityDebugProxy))] public class ClaimsIdentity : IIdentity { private enum SerializationMask @@ -933,5 +936,38 @@ protected virtual void GetObjectData(SerializationInfo info, StreamingContext co { throw new PlatformNotSupportedException(); } + + internal string DebuggerToString() + { + // DebuggerDisplayAttribute is inherited. Use virtual members instead of private fields to gather data. + int claimsCount = 0; + foreach (Claim item in Claims) + { + claimsCount++; + } + + return $"Identity Name = {Name ?? "(null)"}, IsAuthenticated = {IsAuthenticated}, Claims Count = {claimsCount}"; + } + + private sealed class ClaimsIdentityDebugProxy + { + private readonly ClaimsIdentity _identity; + + public ClaimsIdentityDebugProxy(ClaimsIdentity identity) + { + _identity = identity; + } + + public ClaimsIdentity? Actor => _identity.Actor; + public string? AuthenticationType => _identity.AuthenticationType; + public object? BootstrapContext => _identity.BootstrapContext; + // List type has a friendly debugger view + public List Claims => new List(_identity.Claims); + public bool IsAuthenticated => _identity.IsAuthenticated; + public string? Label => _identity.Label; + public string? Name => _identity.Name; + public string NameClaimType => _identity.NameClaimType; + public string RoleClaimType => _identity.RoleClaimType; + } } } diff --git a/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsPrincipal.cs b/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsPrincipal.cs index a423bfa4ce4712..1e1efd8eba6268 100644 --- a/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsPrincipal.cs +++ b/src/libraries/System.Security.Claims/src/System/Security/Claims/ClaimsPrincipal.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.IO; using System.Runtime.Serialization; using System.Security.Principal; @@ -13,6 +14,8 @@ namespace System.Security.Claims /// /// Concrete IPrincipal supporting multiple claims-based identities /// + [DebuggerDisplay("{DebuggerToString(),nq}")] + [DebuggerTypeProxy(typeof(ClaimsPrincipalDebugProxy))] public class ClaimsPrincipal : IPrincipal { private enum SerializationMask @@ -567,5 +570,44 @@ protected virtual void GetObjectData(SerializationInfo info, StreamingContext co { throw new PlatformNotSupportedException(); } + + private string DebuggerToString() + { + // DebuggerDisplayAttribute is inherited. Use virtual members instead of private fields to gather data. + int identitiesCount = 0; + foreach (ClaimsIdentity items in Identities) + { + identitiesCount++; + } + + int claimsCount = 0; + foreach (Claim item in Claims) + { + claimsCount++; + } + + // Return debug string optimized for the case of one identity. + if (identitiesCount == 1 && Identity is ClaimsIdentity claimsIdentity) + { + return $"Principal {claimsIdentity.DebuggerToString()}"; + } + + return $"Principal Identities Count: {identitiesCount}, Claims Count: {claimsCount}"; + } + + private sealed class ClaimsPrincipalDebugProxy + { + private readonly ClaimsPrincipal _principal; + + public ClaimsPrincipalDebugProxy(ClaimsPrincipal principal) + { + _principal = principal; + } + + // List type has a friendly debugger view + public List Claims => new List(_principal.Claims); + public List Identities => new List(_principal.Identities); + public IIdentity? Identity => _principal.Identity; + } } }