diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/Json/JsonClaimSet.cs b/src/Microsoft.IdentityModel.JsonWebTokens/Json/JsonClaimSet.cs index 7bcfb4d4ce..7ad045fc9c 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/Json/JsonClaimSet.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/Json/JsonClaimSet.cs @@ -28,7 +28,7 @@ internal class JsonClaimSet internal JsonClaimSet() { - _jsonClaims = new Dictionary(); + _jsonClaims = []; } internal JsonClaimSet(Dictionary jsonClaims) diff --git a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebToken.cs b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebToken.cs index 48af759d86..021ce54a41 100644 --- a/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebToken.cs +++ b/src/Microsoft.IdentityModel.JsonWebTokens/JsonWebToken.cs @@ -86,6 +86,29 @@ public JsonWebToken(string jwtEncodedString) _encodedToken = jwtEncodedString; } + /// + /// Initializes a new instance of from a ReadOnlyMemory{char} in JWS or JWE Compact serialized format. + /// + /// A ReadOnlyMemory{char} containing the JSON Web Token serialized in JWS or JWE Compact format. + /// A custom delegate to be called when each header claim is being read. If null, default implementation is called. + /// A custom delegate to be called when each payload claim is being read. If null, default implementation is called. + public JsonWebToken( + ReadOnlyMemory encodedTokenMemory, + ReadTokenHeaderValueDelegate readTokenHeaderValueDelegate, + ReadTokenPayloadValueDelegate readTokenPayloadValueDelegate) + { + if (encodedTokenMemory.IsEmpty) + throw LogHelper.LogExceptionMessage(new ArgumentNullException(nameof(encodedTokenMemory))); + + ReadTokenHeaderValueDelegate = readTokenHeaderValueDelegate ?? ReadTokenHeaderValue; + ReadTokenPayloadValueDelegate = readTokenPayloadValueDelegate ?? ReadTokenPayloadValue; + + ReadToken(encodedTokenMemory); + + _encodedTokenMemory = encodedTokenMemory; + + } + /// /// Initializes a new instance of from a ReadOnlyMemory{char} in JWS or JWE Compact serialized format. /// @@ -141,6 +164,43 @@ public JsonWebToken(string header, string payload) _encodedToken = encodedToken; } + /// + /// Called for each claim when token header is being read. + /// + /// + /// An example implementation: + /// + /// object ReadPayloadValueDelegate(ref Utf8JsonReader reader, string claimName) => + /// { + /// if (reader.ValueTextEquals("CustomProp")) + /// { + /// return JsonSerializerPrimitives.ReadString(ref reader, JwtRegisteredClaimNames.CustomProp, ClassName, true); + /// } + /// return JsonWebToken.ReadTokenHeaderValue(ref reader, claimName); + /// } + /// + /// + internal ReadTokenHeaderValueDelegate ReadTokenHeaderValueDelegate { get; set; } = ReadTokenHeaderValue; + + + /// + /// Called for each claim when token payload is being read. + /// + /// + /// An example implementation: + /// + /// object ReadPayloadValueDelegate(ref Utf8JsonReader reader, string claimName) => + /// { + /// if (reader.ValueTextEquals("CustomProp")) + /// { + /// return JsonSerializerPrimitives.ReadString(ref reader, JwtRegisteredClaimNames.CustomProp, ClassName, true); + /// } + /// return JsonWebToken.ReadTokenPayloadValue(ref reader, claimName); + /// } + /// + /// + internal ReadTokenPayloadValueDelegate ReadTokenPayloadValueDelegate { get; set; } = ReadTokenPayloadValue; + internal string ActualIssuer { get; set; } internal ClaimsIdentity ActorClaimsIdentity { get; set; } diff --git a/src/Microsoft.IdentityModel.Tokens/Delegates.cs b/src/Microsoft.IdentityModel.Tokens/Delegates.cs index e116fc4662..89b922ff5d 100644 --- a/src/Microsoft.IdentityModel.Tokens/Delegates.cs +++ b/src/Microsoft.IdentityModel.Tokens/Delegates.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Text.Json; using System.Threading.Tasks; namespace Microsoft.IdentityModel.Tokens @@ -206,4 +207,22 @@ namespace Microsoft.IdentityModel.Tokens /// The validated . internal delegate ValidationResult SignatureValidationDelegate(SecurityToken token, ValidationParameters validationParameters, BaseConfiguration? configuration, CallContext? callContext); #nullable restore + + /// + /// Definition for ReadTokenHeaderValueDelegate. + /// Called for each claim when token header is being read. + /// + /// Reader for the underlying token bytes. + /// The name of the claim being read. + /// + public delegate object ReadTokenHeaderValueDelegate(ref Utf8JsonReader reader, string claimName); + + /// + /// Definition for ReadTokenPayloadValueDelegate. + /// Called for each claim when token payload is being read. + /// + /// Reader for the underlying token bytes. + /// The name of the claim being read. + /// + public delegate object ReadTokenPayloadValueDelegate(ref Utf8JsonReader reader, string claimName); } diff --git a/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs b/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs index 7ea251d8dc..bed3156450 100644 --- a/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs +++ b/src/Microsoft.IdentityModel.Tokens/TokenValidationParameters.cs @@ -449,6 +449,16 @@ public string NameClaimType /// public IDictionary PropertyBag { get; set; } + /// + /// Gets or sets a delegate that will be called when reading token payload claims. + /// + public ReadTokenHeaderValueDelegate ReadTokenHeaderValue { get; set; } + + /// + /// Gets or sets a delegate that will be called when reading token payload claims. + /// + public ReadTokenPayloadValueDelegate ReadTokenPayloadValue { get; set; } + /// /// Gets or sets a boolean to control if configuration required to be refreshed before token validation. /// diff --git a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/CustomJsonWebToken.cs b/test/Microsoft.IdentityModel.JsonWebTokens.Tests/CustomJsonWebToken.cs deleted file mode 100644 index 813b82e4b3..0000000000 --- a/test/Microsoft.IdentityModel.JsonWebTokens.Tests/CustomJsonWebToken.cs +++ /dev/null @@ -1,42 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text.Json; -using Microsoft.IdentityModel.Tokens.Json; - -namespace Microsoft.IdentityModel.JsonWebTokens.Tests -{ - public class CustomJsonWebToken : JsonWebToken - { - private const string CustomClaimName = "CustomClaim"; - - public CustomJsonWebToken(string jwtEncodedString) : base(jwtEncodedString) { } - - public CustomJsonWebToken(ReadOnlyMemory encodedTokenMemory) : base(encodedTokenMemory) { } - - public CustomJsonWebToken(string header, string payload) : base(header, payload) { } - - private protected override void ReadPayloadValue(ref Utf8JsonReader reader, IDictionary claims) - { - if (reader.ValueTextEquals(CustomClaimName)) - { - _customClaim = JsonSerializerPrimitives.ReadString(ref reader, CustomClaimName, ClassName, true); - claims[CustomClaimName] = _customClaim; - } - else - { - base.ReadPayloadValue(ref reader, claims); - } - } - - private string _customClaim; - - public string CustomClaim - { - get - { - _customClaim ??= Payload.GetStringValue(CustomClaimName); - return _customClaim; - } - } - } -}